写这篇文章的背景是由于以前遇到的,在跨域的状况下经过 axios 发起的 get 请求正常,post 请求会在正式请求发送以前先发送一个 opstions 请求,然后端接口没有兼容 options,致使 404 的状况。前端
而在解决这个问题时带着好奇心顺带查了一下,给本身补充了些知识点。ios
简单讲,从 JavaScript
代码发起的 XMLHttpRequest
请求能够分为两种:json
不会触发CORS预检
的请求,而是直接向服务端发送请求,什么是 CORS预检
我们后面说,其匹配的规则大体以下:axios
GET
、 HEAD
、 POST
中的一种ACCEPT
Accept-Language
Content-Language
DPR
Downlink
Save-Data
Viewport-Width
Width
Content-Type (值仅限text/plain,multipart/form-data,application/x-www-form-urlencoded)
XMLHttpRequestUpload
对象没有注册任何事件监听ReadableStream
对象在发送正式请求以前,会先发起一个 OPTIONS
预检请求到服务器,以获知服务器是否容许该实际请求,若不容许,则再也不发送请求,其匹配规则以下:后端
PUT
、 DELETE
、 CONNECT
、 OPTIONS
、 TRACE
、 PATCH
之一CORS安所有首字段集合
以外的字段XMLHttpRequestUpload
对象注册了任意事件监听器ReadableStream
对象在跨域请求中,若服务端返回了正确的跨域响应部首:Access-Control-Allow-Origin
、Access-Control-Allow-Method
、Access-Control-Allow-Headers
, 则跨域请求能正常获取数据。api
根据以上了解的知识点,跟进遇到的问题,发现 axios 的请求部首 Content-Type
的值默认为 application/json;charset=utf-8
,且 POST
请求数据为 json
格式,故进行 POST
请求会先发出预检请求,若服务端对预检请求的响应为不支持,则请求终止。跨域
根据上面分析出的缘由,如下列举两种解决方案:安全
使服务端接口支持 OPTIONS
方法,且对跨域预检请求的请求部首进行完整的响应匹配,代表服务器将接受后续的实际请求,则实际请求将被正常响应。服务器
跨域时将请求转换为简单请求:cookie
Content-Type
设为 application/x-www-form-urlencoded
POST
请求数据,方式有如下两种:
URLSearchParams
生成POST
请求的数据qs
库的 stringify
api 对请求数据进行转换(若请求数据中某个字段的值为引用类型,须要先经过 JSON.stringify 处理,以防止服务端没法识别)例子:
/* 经过 qs 模块处理请求数据*/
import axios from 'axios'
import qs from 'qs'
axios.defaults.withCredentials = true // 若跨域请求须要带 cookie 身份识别
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
// 请求拦截器
axios.interceptors.request.use(req => {
// 对 post 请求数据进行处理
if (req.method === 'post') {
Object.keys(req.data).forEach(item => {
!isPrimeval(req.data[item]) && (req.data[item] = JSON.stringify(req.data[item]))
})
req.data = qs.stringify(req.data)
}
return req
}, error => {
// 请求出错时处理
return Promise.reject(error)
})
or
/* 经过 URLSearchParams 生成 POST 请求数据 */
import axios from 'axios'
async function anInterface (url, params = {}) {
let data = new URLSearchParams()
for(let key in params) {
data.append(params[key])
}
const res = await axios.post(url, data)
// 处理数据
return res.data
}
复制代码
经过以上方式便可将 POST
预检请求转换为简单请求,其好处不言而喻,对于多个 POST
请求而言,能够减小一半的请求数量,且在一些服务端比较不能改动的场景更为适用。
以上为本次文章全部内容,如有问题,望指正;若需转载,望注明出处