前端简单请求&非简单请求
问题背景
Vue项目里用axios调用一个公共开放的API服务(该服务已经设置Access-Control-Allow-Origin:*)
问题表现
在axios服务里面的代码(部分逻辑代码已省略)
// request.js …… axios.defaults.withCredentials = true; axios.defaults.crossDomain = true; axios.interceptors.request.use(config => { …… config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`; config.headers[website.tokenHeader] = 'bearer ' + getToken() config.headers["Content-Type"] = "text/plain"; …… }) …… // index.js export const getData = () => request({ url: 'http://location.tianditu.gov.cn/data/getCityName?callback=query', method: 'get' }); // index.vue getData().then(res => { const data = res.data; }) 复制代码
在axios服务的报错信息
请求头信息
明明是开放的第三方公共API,用postman调用人家的Access-Control-Allow-Origin已经设置了*,却显示跨域的报错信息?我表示不服,于是三下五除二在当前项目引入了JQuery,用$大法发起ajax请求
$.ajax({ type:"get", url:"http://location.tianditu.gov.cn/data/getCityName?callback=query", success: function(data) { console.log(data) } }); 复制代码
初步结论
这个带些玄学色彩的接口,用JQuery大法请求是正常的,用axios请求报跨域
于是我就各种谷歌,依然毫无头绪,有些大佬也遇到过这样的问题,提出来过但是并没有给除一个完美的解释,就在我准备放弃的时候,突然不小心扫到阮一峰老师五年前的一篇跨域资源共享 CORS 详解
浏览器的两种请求
浏览器将请求分为两大类:简单请求(simple request)和非简单请求(not-so-simple request)
简单请求(需要同时满足以下两大条件)
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
HEAD
GET
POST
请求方法是以下三种方法之一
HTTP的头信息不超出以下几种字段:
非简单请求(凡是不是简单请求的,就是非简单请求)
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或者DELETE,或者content-type是application/json。非简单请求会在正式通信之前,增加一次HTTP的查询请求,称为“预检”请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的
XMLHttpRequest
请求,否则就报错。
哥德巴赫猜想
axios跨域是因为用axios发起了一个非简单请求,而JQuery大法只是一个简单的请求,跨域正是因为非简单请求的preflight
axios服务发起的非简单请求
$.ajax发起的简单请
总结
之前封装的axios服务,带来太多非必要的请求头信息,导致简单请求变成非简单请求,非简单请求又发起了了一个preflight,而该第三方服务对预检请求处理可能出了些问题,导致浏览器误认为这是一次跨域的请求
还是之前的axios服务,剔除掉冗余的header信息或者用一个new的axios,依然可以愉快的正常发起简单请求
作者:码上人生
链接:https://juejin.cn/post/7018072458456481829