最近公司布置了一个公众号网页项目,正好有段时间没用Vue来搭建项目了,想一想仍是从Vue作起,正好如今脚手架也到3.0了,试试锋利不锋利。而后就遇到了很多坑。ios
Vue搭建完该请求接口调试,天然是用官方推荐的Axios了,而后就遇到了一个小问题,正常的Post请求,莫名其妙的变为了OPTIONS请求。npm
平时开发最多见最经常使用的HTTP请求应该是POST和GET。可是HTTP所提供的请求方法却不止一种。axios
至于这些方法具体的应用,这里就不作论述了跨域
在代码中明明是Post的请求,可是在谷歌控制面板中却显示的是OPTIONS,这是为何? 浏览器
期初想着多是跨域的问题,而后让后台加了响应头,可是问题并没解决。后来根据英文提示请求违反CORS协议,去MDN上查询了什么事CORS。安全
翻阅MDN关于CORS介绍后(CORS介绍连接),在功能概述中后看到这样一段话:bash
跨域资源共享标准(CORS:cross-origin sharing standard )新增了一组 HTTP首部字段,容许服务器声明哪些源站经过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生反作用的 HTTP 请求方法(特别是 GET 之外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否容许该跨域请求。服务器确认容许以后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也能够通知客户端,是否须要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。CORS请求失败会产生错误,可是为了安全,在JavaScript代码层面是没法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。服务器
意思就是对于跨域的请求,除了GET外或者搭配某些 MIME 类型的 POST 请求,都会先发送一次OPTIONS的预请求,用来检测服务端是否容许该跨域请求。因此对于不符合规范的POST请求就会被挡到外面,因此才会产生如上的报错,只发送了OPTIONS请求,而重要的POST没有发送。app
既然知道问题出在哪里,那就须要让发送的请求符合CORS协议。而根据报错所给的提示 Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response. 结合控制面板上面请求头的信息,发现Access-Control-Allow-Headers的content-type不符合要求,因此才会触发CORS检测。post
既然知道了请求被改变的缘由是由于触发了CORS检测,那么只要符合CORS的规范,规避检测,就能够保证成功。在查阅资料后发现有以下内容,可以规避检测。MDN原文以下(简单请求):
某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch (其中定义了 CORS)规范。若请求知足全部下述条件,则该请求可视为“简单请求”:
请注意上面要求的是知足全部条件。而结合控制面板的信息,以及报错信息,所发送的信息格式不属于Content-Type中的任意一种。因此触发了CORS检测,致使POST请求不成功。那么下面只须要使参数的格式是上面Content-Type中所要求的其中一种就能够了。
而我当时所向后台传递的是一个参数未经处理的Object对象,不属于上面三种类型中的一种,因此解决方案就是对传递的参数进行处理知足要求。
对参数进行字符串转换
根绝以往的开发经验,对参数进行JSON.stringify()
处理后,能够看到请求已经能走通,可是传递给后台的参数,并非后台想要的。因此这样做可能须要后台的配合。 PS:上一家公司就是这样处理参数的,因此这里也是验证猜想,没想到确实有点用。
能够看到参数是字符串的形式。
在 axios 中,可使用 URLSearchParams API
var data = new URLSearchParams();
data.append('id', '1');
data.append('name', 'minmin');
data.append('age', '23')
axios.post('url, data).then( res => { ... } ) 复制代码
可是有一点不方便,若是参数特别多的话,这种方式费事费力,因此仍是用插件解决吧
用插件解决,在项目中引用qs
npm install --save qs
安装不上的用淘宝镜像,而后
cnpm install --save qs
复制代码
//封装请求方法,全部参数统一用qs.stringify(data)处理
function httpRequest(url, method, data) {
let rdata = { ...publicData, ...data }
rdata = qs.stringify(rdata)
if (method === "post") {
return post(url, rdata)
} else {
return get(url, rdata)
}
}
复制代码
我的仍是建议在项目中使用插件解决吧,每次经过append参数费时又费力,固然若是公司用的是第一种向后台传参,不用插件也没什么问题。