Fetch接口请求

1.npm安装cnpm install --save isomorphic-fetch es6-promise
2.由于ie不支持Promise,所以需要安装promise-polyfill;

cnpm install promise-polyfill --save-exact

3.需要在index.js中引用

import Promise from "promise-polyfill";
if(!window.Promise){
window.Promise = Promise;
}

4.配置文件封装

//前置拼接url
let api = '域名地址';

//处理promise和fetch的兼容性以及引入
require('es6-promise').polyfill();
require('isomorphic-fetch');

//处理get请求,传入参数对象拼接
let formatUrl = obj => {
  let params = Object.values(obj).reduce((a, b, i) => `${a}${Object.keys(obj)[i]}=${b}&`, '?');
  return params.substring(0, params.length - 1);
};

let Fetch = (url, option = {}) => {
  option.headers = option.headers || {};
  // option.headers['pl'] = 'admin';
  // option.headers['token'] = `${window.localStorage.getItem('token')}`; //是否使用headers带去token等参数
  const m = (option.method || '').toLocaleLowerCase();
  // get query format
  if (m == 'get') {
    if (option.query) {
      url = url + formatUrl(option.query);
    }
  }
  //对非get类请求头和请求体做处理
  if (m === 'post' || m === 'put' || m === 'delete') {
    option.headers['Content-Type'] = option.headers['Content-Type'] || 'application/json';
    option.body = JSON.stringify(option.body);
    // option.body = qs.stringify(option.body) //根据后台要求,如果有时候是java请求会用qs转
  }
  return new Promise((resolve, reject) => {
    fetch(api + url, option)
      .then(response => {
        status = response.status;
        if (response.status >= 500) {
          Fetch.systemError && Fetch.systemError('系统错误');
        }
        return response;
      })
      .then(parseJSON)
      .then(response => {
        response.status = status;
        if (response.status >= 401) {
          if (response.state == 8888) {
            //登陆超时返回状态吗

            Fetch.overTime && Fetch.overTime(response);
          }
          if (response.state == 6666) {
            //没有权限返回状态码
          }
        }
        resolve(response);
      })
      .catch(error => {
        console.log('err', error);
        Fetch.otherError && Fetch.otherError(error.message);
      });
  });
};

//response 转化
function parseJSON(response) {
  return response.json();
}

export default Fetch;

5…请求使用

async ApiFetchlist(e){
        let query={id:e};//参数
        let reslist = await this.Fetch('logic/apply/getGoods', {
          method: 'get',
          query
        });
        // console.log(reslist);
        this.morelist = reslist.data;
      }

注意在使用async及await是要注意一起使用

<think>我们正在处理一个前端开发问题:如何为所有fetch请求统一添加基础路径。 根据引用内容,我们可以通过几种方式来实现: 1. 在每次fetch请求时手动添加基础路径(但这样不统一,且容易出错) 2. 使用环境变量来管理基础路径,并在请求时拼接(但还是要每次写) 3. 封装fetch函数,在封装函数内部自动添加基础路径(推荐) 4. 使用代理(如vite的proxy)来重写路径(这主要解决跨域,但也可以用于路径转换,不过是在开发服务器层面) 用户的需求是统一添加path(基础路径),因此我们重点考虑封装fetch或使用代理。 但是注意:代理配置(如vite.config.js中的proxy)通常用于开发环境,将特定前缀的请求转发到目标服务器,并去掉前缀(如引用[3]所示)。但用户的需求是“统一添加路径”,也就是在每次请求的URL前面加上一个基础路径(比如'/api'),这个基础路径可能是后端接口的统一前缀。 因此,我们有两种主要方法: 方法一:封装fetch函数,自动在传入的url前加上基础路径。 方法二:使用环境变量,然后通过封装函数或者配置全局变量来使用。 我们推荐方法一,因为这样可以在代码中集中管理,且适用于生产环境和开发环境。 具体步骤: 1. 创建一个封装的fetch函数,例如myFetch。 2. 在这个函数中,将基础路径(比如'/api')和传入的相对路径拼接(注意处理斜杠问题)。 3. 使用这个封装函数代替原生的fetch。 另外,我们也可以考虑使用第三方库(如axios)有baseURL配置,但用户要求使用fetch,所以我们可以自己封装。 示例代码: 首先,我们可以定义一个基础路径,例如: ```javascript const BASE_URL = '/api'; // 这里可以是实际的基础路径,也可以从环境变量中读取 ``` 然后封装: ```javascript async function myFetch(url, options) { // 拼接完整的URL const fullUrl = `${BASE_URL}${url}`; return fetch(fullUrl, options); } ``` 使用: ```javascript myFetch('/students').then(...) ``` 但是,这里有一个潜在问题:如果传入的url已经是绝对路径(比如以http开头),我们不应该再加基础路径。所以我们需要判断: 改进: ```javascript function getFullUrl(url) { // 如果url以http://或https://开头,或者是绝对路径(以/开头,且我们不想再加基础路径?),这里我们只处理相对路径的情况 // 通常,我们只对相对路径(不以http开头的,且不是以双斜杠开头的)添加基础路径 if (url.startsWith('http://') || url.startsWith('https://')) { return url; } // 注意:基础路径和传入的url之间可能有多余的斜杠,我们可以用正则处理,或者确保BASE_URL以斜杠结尾,url不以斜杠开头(或者反过来) // 这里我们简单处理:如果BASE_URL以斜杠结尾,而url以斜杠开头,则去掉一个 // 或者我们可以用new URL(url, base)的方式,但注意base必须是绝对路径(如果是在浏览器环境,我们可以用当前页面的基础路径,但这里我们用的是自定义的BASE_URL,所以需要确保BASE_URL是绝对路径,通常以斜杠开头) // 简单拼接,并处理双斜杠问题 let base = BASE_URL; if (base.endsWith('/') && url.startsWith('/')) { base = base.slice(0, -1); // 去掉结尾的斜杠 } else if (!base.endsWith('/') && !url.startsWith('/')) { base = base + '/'; } return base + url; } async function myFetch(url, options) { const fullUrl = getFullUrl(url); return fetch(fullUrl, options); } ``` 但是,上面的处理可能还不够完善。更简单的方式是要求BASE_URL以斜杠结尾,url不以斜杠开头(或者反过来),然后在代码中规范使用。 另一种更简洁的方式:使用URL构造函数(推荐): ```javascript function getFullUrl(url) { // 如果已经是绝对URL,直接返回 if (url.startsWith('http')) { return url; } // 假设我们的BASE_URL是一个绝对路径(以/开头,例如'/api'),并且我们当前页面是在域名根目录下,那么我们可以这样: // 注意:如果BASE_URL是相对路径,那么需要相对于当前页面,但我们通常用绝对路径(以/开头) // 使用当前页面的origin作为基础,然后拼接BASE_URL和url const base = window.location.origin + BASE_URL; // 使用URL构造函数可以避免双斜杠问题 return new URL(url, base).href; } ``` 但是,这里要注意:如果BASE_URL是相对路径,那么使用new URL(url, base)时,base需要是绝对路径。所以BASE_URL应该以斜杠开头(如'/api'),这样base就是`http://当前域名/api`。 所以,我们可以这样写: ```javascript const BASE_URL = '/api'; // 必须以斜杠开头 function getFullUrl(url) { // 绝对URL直接返回 if (url.startsWith('http://') || url.startsWith('https://')) { return url; } const base = window.location.origin + BASE_URL; return new URL(url, base).href; } ``` 但是,如果我们的BASE_URL是一个完整的URL(比如部署在不同域名下),那么我们可以直接设置BASE_URL为那个域名,然后传入相对路径。 因此,我们可以让BASE_URL是一个绝对路径(以http开头)或者是一个以斜杠开头的路径。 修改一下: ```javascript const BASE_URL = process.env.BASE_URL || '/api'; // 可以配置为绝对URL,也可以是以斜杠开头的路径 function getFullUrl(url) { // 如果BASE_URL是绝对URL(以http开头),那么直接用它作为基础 // 如果BASE_URL是以斜杠开头的路径,那么拼接在origin后面 if (BASE_URL.startsWith('http')) { return new URL(url, BASE_URL).href; } else { // 如果BASE_URL不是以http开头,我们就认为它是相对于当前域名的路径 const base = window.location.origin + BASE_URL; return new URL(url, base).href; } } ``` 这样更通用。 然后,在封装的myFetch中使用这个getFullUrl。 但是,注意:在服务端渲染(如Node.js)中没有window对象,所以如果代码需要在服务端运行,需要避免使用window。这里假设是纯浏览器环境。 另外,引用[2]中提到,在请求时可以添加headers等,我们的封装也要支持options。 所以,完整的封装: ```javascript const BASE_URL = '/api'; // 或者从环境变量中读取 async function myFetch(url, options = {}) { const fullUrl = getFullUrl(url); try { const response = await fetch(fullUrl, options); // 可以在这里统一处理响应,例如检查状态码等 return response; } catch (error) { // 统一错误处理 console.error('Fetch error:', error); throw error; } } function getFullUrl(url) { if (url.startsWith('http://') || url.startsWith('https://')) { return url; } // 处理BASE_URL if (BASE_URL.startsWith('http')) { return new URL(url, BASE_URL).href; } // 否则,BASE_URL是相对于当前域名的路径 const base = window.location.origin + BASE_URL; return new URL(url, base).href; } ``` 使用示例: ```javascript myFetch('/students', { headers: { 'Content-Type': 'application/json', 'token': 'xxx' } }).then(...) ``` 这样,我们就实现了统一添加基础路径。 另外,引用[3]提到了使用代理(proxy)来重写路径。这种方法是在开发服务器层面将特定前缀的请求转发到目标服务器。例如,在vite.config.js中配置: ```javascript export default { server: { proxy: { '/api': { target: 'http://your-api-server.com', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } } ``` 这样,在开发环境中,前端请求`/api/students`会被代理到`http://your-api-server.com/students`。但是,这种方法只适用于开发环境,生产环境需要前端代码直接请求正确的路径(可能是生产环境的API地址)。所以,我们通常会在生产环境将BASE_URL设置为生产环境的基础路径(可能是空,如果前端和后端在同一域名下,且接口路径就是/api的话),而在开发环境,我们可能将BASE_URL设置为`/api`,然后通过代理去掉这个前缀并转发到开发服务器。 因此,代理和基础路径的配置是配合使用的。在开发环境,我们设置BASE_URL为代理的前缀(如'/api'),然后代理会去掉这个前缀并转发到目标服务器;在生产环境,我们设置BASE_URL为空(如果前端和后端在同一域名下,且接口路径就是根路径)或者设置为生产环境的基础路径(如'/prod-api')。 总结: 1. 封装fetch函数,统一添加基础路径(通过环境变量配置BASE_URL)。 2. 开发环境通过代理解决跨域和路径重写问题。 3. 生产环境则直接请求配置的基础路径(与前端同域或不同域)。 这样,我们就实现了统一添加基础路径的需求。 相关问题: 1. 如何根据环境(开发、生产)设置不同的基础路径? 2. 除了封装fetch,还有哪些方法可以统一管理请求路径? 3. 在Vue或React项目中,如何配置代理以支持开发环境的基础路径转发?</think>### 前端统一配置 fetch 请求基础路径的方法 可以通过以下两种方式实现为所有 fetch 请求统一添加基础路径: #### 方法一:封装 fetch 函数(推荐) ```javascript // 配置基础路径 const BASE_PATH = '/api'; // 统一添加的基础路径 // 封装 fetch 函数 const customFetch = async (url, options = {}) => { // 拼接完整路径 const fullUrl = `${BASE_PATH}${url.startsWith('/') ? url : `/${url}`}`; try { // 发起请求 const response = await fetch(fullUrl, { ...options, headers: { 'Content-Type': 'application/json', ...(options.headers || {}) } }); // 统一处理响应 if (!response.ok) throw new Error(`请求失败: ${response.status}`); return response.json(); } catch (error) { console.error('请求错误:', error); throw error; } }; // 使用示例 const fetchData = async () => { const data = await customFetch('/students'); // 实际请求路径变为 /api/students console.log(data); }; ``` #### 方法二:使用环境变量 + 请求拦截 ```javascript // .env 文件 VITE_API_BASE_URL = '/api' // 请求工具文件 const baseURL = import.meta.env.VITE_API_BASE_URL; export const request = (url, options) => { return fetch(`${baseURL}${url}`, options); }; // 使用示例 import { request } from './fetchUtils'; request('/students').then(...); ``` #### 结合代理配置(开发环境) 在 `vite.config.js` 中配置代理: ```javascript // vite.config.js export default { server: { proxy: { '/api': { // 匹配基础路径 target: 'https://your-api-server.com', changeOrigin: true, rewrite: path => path.replace(/^\/api/, '') // 移除基础路径前缀 } } } } ``` ### 关键说明 1. **路径处理**: - 自动处理斜杠问题:`${BASE_PATH}${url.startsWith('/') ? url : `/${url}`}` - 支持绝对路径检查:如果传入完整 URL 则跳过拼接 2. **环境管理**: - 开发环境:通过代理解决跨域(如引用[3]所示) - 生产环境:直接请求真实 API 地址 3. **统一拦截**: - 可集中添加认证头(如引用[2]的 token) - 统一错误处理逻辑 - 响应数据格式预处理 4. **TypeScript 支持**(可选): ```typescript declare global { interface Window { ENV: { API_BASE: string; }; } } ``` > **最佳实践建议**:对于大型项目,推荐使用 axios 等库的 `baseURL` 配置,或采用 Redux Toolkit Query 等框架的内置路径管理功能,可更优雅地实现统一路径配置[^1][^2][^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值