Fetch
Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。
它还提供了一个全局 fetch() 方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
这种功能以前是使用 XMLHttpRequest 实现的。
Fetch 提供了一个更理想的替代方案,可以很容易地被其他技术使用,例如 Service Workers。
Fetch 还提供了专门的逻辑空间来定义其他与 HTTP 相关的概念,例如 CORS 和 HTTP 的扩展。
请注意,fetch 规范与 jQuery.ajax() 主要有以下的不同:
- 当接收到一个代表错误的 HTTP 状态码时,从 fetch() 返回的 Promise 不会被标记为 reject,即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve(如果响应的 HTTP 状态码不在 200 - 299 的范围内,则设置 resolve 返回值的 ok 属性为 false),仅当
网络故障
时或请求被阻止
时,才会标记为 reject。 - fetch 不会发送跨域 cookie,除非你使用了 credentials 的初始化选项。
一个基本的 fetch 请求设置起来很简单。看看下面的代码:
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => console.log(data));
参考 fetch(),查看所有可选的配置和更多描述。
// Example POST method implementation:
async function postData(url = '', data = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
return response.json(); // parses JSON response into native JavaScript objects
}
postData('https://example.com/answer', { answer: 42 })
.then(data => {
console.log(data); // JSON data parsed by `data.json()` call
});
注意:mode: "no-cors" 仅允许使用一组有限的 HTTP 请求头:
- Accept
- Accept-Language
- Content-Language
- Content-Type 允许使用的值为:application/x-www-form-urlencoded、multipart/form-data 或 text/plain
MDN地址: https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Us...
qs简介
一个带有一些附加安全性的查询字符串解析和字符串化库。
主要维护者:Jordan Harband
最初创建者和维护者:TJ Holowaychuk
npmjs仓库地址: https://www.npmjs.com/package/qs
react 使用qs
安装
npm install qs
import qs from'qs'
qu.stringify()和qs.parse()
- qu.stringify() :将
对象序列化成url的形式
;以&
进行拼接 - qs.parse():将url解析成对象形式;
1、qs.parse() 将URL解析成对象的形式
import Qs from 'qs';
let url = 'method=query_sql_dataset_d<a style="color:transparent">来源gao*daima.com搞@代#码网</a>ata&projectId=85&appToken=7d22e38e-5717-11e7-907b-a6006ad3dba0';
Qs.parse(url);
console.log(Qs.parse(url));
输出结果
{
method:'query_sql_dataset_data',
projectId:'85',
appToken:'7d22e38e-5717-11e7-907b-a6006ad3dba0'
}
2、qs.stringify()将对象序列化成URL的形式,以&进行拼接(可用于发送查询条件)
import Qs from 'qs';
let obj= {
method: "query_sql_dataset_data",
projectId: "85",
appToken: "7d22e38e-5717-11e7-907b-a6006ad3dba0",
datasetId: " 12564701"
};
Qs.stringify(obj);
console.log(Qs.stringify(obj));
输出的是:
method=query_sql_dataset_data&projectId=85&appToken=7d22e38e-5717-11e7-907b-a6006ad3dba0&datasetId=%12564701
JSON.stringify(param) VS Qs.stringify(param),
JSON中同样存在stringify方法,但是和Qs.stringify之间的区别是很明显的
// JSON.stringify(param)
{"uid":"cs11","pwd":"000000als","username":"cs11","password":"000000als"}
// Qs.stringify(param)
uid=cs11&pwd=000000als&username=cs11&password=000000als
封装fetch
为什么封装Fetch请求
- 请求的地方代码更少。
- 公共的错误统一一个地方添加即可。
- 请求定制的错误还是请求自己也可以处理。
- 扩展性好,添加功能只需要改一个地方。
总结起来一句话:简单,好用
封装Fetch请求(主要文件)
"./fetchUtil"
import qs from 'qs';
import { message } from 'antd';
const { stringify, parse } = qs;
const checkStatus = res => {
if (200 >= res.status < 300) {
return res;
}
message.error(`网络请求失败,${res.status}`);
const error = new Error(res.statusText);
error.response = error;
throw error;
};
/**
* 捕获成功登录过期状态码等
* @param res
* @returns {*}
*/
const judgeOkState = async res => {
const cloneRes = await res.clone().json();
//TODO:可以在这里管控全局请求
if (!!cloneRes.code && cloneRes.code !== 200) {
message.error(`11${cloneRes.msg}${cloneRes.code}`);
}
return res;
};
/**
* 捕获失败
* @param error
*/
const handleError = error => {
if (error instanceof TypeError) {
message.error(`网络请求失败啦!${error}`);
}
return { //防止页面崩溃,因为每个接口都有判断res.code以及data
code: -1,
data: false,
};
};
class http {
/**
*静态的fetch请求通用方法
* @param url
* @param options
* @returns {Promise<unknown>}
*/
static async staticFetch(url = '', options = {}) {
const defaultOptions = {
/*允许携带cookies*/
credentials: 'include',
/*允许跨域**/
mode: 'cors',
headers: {
token: null,
Authorization: null,
// 当请求方法是POST,如果不指定content-type是其他类型的话,默认为如下,要求参数传递样式为 key1=value1&key2=value2,但实际场景以json为多
// 'content-type': 'application/x-www-form-urlencoded',
},
};
if (options.method === 'POST' || 'PUT') {
defaultOptions.headers['Content-Type'] = 'application/json; charset=utf-8';
}
const newOptions = { ...defaultOptions, ...options };
console.log('newOptions', newOptions);
return fetch(url, newOptions)
.then(checkStatus)
.then(judgeOkState)
.then(res => res.json())
.catch(handleError);
}
/**
*post请求方式
* @param url
* @returns {Promise<unknown>}
*/
post(url, params = {}, option = {}) {
const options = Object.assign({ method: 'POST' }, option);
//一般我们常用场景用的是json,所以需要在headers加Content-Type类型
options.body = JSON.stringify(params);
//可以是上传键值对形式,也可以是文件,使用append创造键值对数据
if (options.type === 'FormData' && options.body !== 'undefined') {
let params = new FormData();
for (let key of Object.keys(options.body)) {
params.append(key, options.body[key]);
}
options.body = params;
}
return http.staticFetch(url, options); //类的静态方法只能通过类本身调用
}
/**
* put方法
* @param url
* @returns {Promise<unknown>}
*/
put(url, params = {}, option = {}) {
const options = Object.assign({ method: 'PUT' }, option);
options.body = JSON.stringify(params);
return http.staticFetch(url, options); //类的静态方法只能通过类本身调用
}
/**
* get请求方式
* @param url
* @param option
*/
get(url, option = {}) {
const options = Object.assign({ method: 'GET' }, option);
return http.staticFetch(url, options);
}
}
const requestFun = new http(); //new生成实例
export const { post, get, put } = requestFun;
export default requestFun;
定义接口文件,导出fetch
utils/api
import requestFun from "./fetchUtil"; //引入
import qs from "qs";
const { stringify } = qs;
const { post, get } = requestFun;
//get方式
export async function fetchData1(params) {
return get(`/api/bbb?${stringify(params)}`);
}
//post方式
export async function fetchData2(params) {
return post(`/api/aaa`, params);
}
export async function fetchGetComments(params) {
return get(`http://localhost:8001/comments`, params);
}
组件内使用
home.js
import {fetchGetComments} from '../../utils/api'
// 获取数据
const loadData = async ()=> {
const commentData = await fetchGetComments();
console.log('commentData')
console.log(commentData)
}
延申问题
如果要扩展fetch的delete和patch,该如何做?
如果自定义header的话,该如何做?
如果post后端需要formdata结构数据又该如何做?
感兴趣的小伙伴,可以自行脑补一下。
参考文档
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。