使用Vue.js跨域请求时遇到的坑

最近在学Vue.js,在从后端请求数据的时候出现了问题。

简单跨域请求

在Vue中直接跨域获取后端数据时,控制台会直接报错:’’’ No ‘Access-Control-Allow-Origin’ ‘’’,
意思是后端没有这个允许跨域的响应头。

解决这个问题的有以下几种方法。

不跨域

这个很好理解,项目生成发布后运行在同一域和端口,就不会发生跨域问题。
不过调试过程中肯定不能总生成静态代码,就需要下面的方法。

JSONP

在页面用标签的src属性引用远程js(实际上是任意的)是可以直接跨域的,所以把数据变成js代码就可以实现数据的跨域了也就是在json包裹成js函数(JSON with Padding)。
页面中大概就是这样子

1
<script src="http://abc.com/api?参数1=<参数1>&参数2=<参数2>&callback=myfunction"><script>

实际使用的时候一般由js动态生成代码,jQuery等库都封装好了。在Vue中可以用vue-resource的 $http.jsonp来操做(vue-resource已经不维护且不推荐了)

而此时服务端返回的应该是

1
myfunction({<json数据>});

由于是函数字符串,所以并不会被执行,而可以在页面中通过调用myfunction来获得其中的数据。

此方法仍需要后端支持jsonp,对于某些支持jsonp的api就不需要跨域了。不过这个方法有个缺点就是只支持get方法,获取数据可以,对于其他的情况就无能为力了。

proxyTable

这个方法也很简单,不过只能用于开发的时候。
proxyTable 是vue-cli带的一个配置参数,顾名思义就是虚拟一个服务端来中转请求。
比如要访问的接口是 a.com/api/xxxx,通过配置proxyTable,获取数据的时候只要 请求当前域(不产生跨域)上的’/api/xxxx’,请求会被发送到a.com/api/xxxx。
具体配置如下:
api下的所有请求都会被转发

1
2
3
4
5
6
7
8
proxyTable: {
'/api': {
target: 'http://a.com',
pathRewrite: {
'^/api': '/api'
}
}
}

详见:https://vuejs-templates.github.io/webpack/proxy.html

后端配置跨域

如果是自己的api后端的话直接配置就好了;如果是一些公开接口啥的,可以试试用自己的后端中转,原理和proxyTable是一样的,如果后端前端不在同一域的话,仍需要配置跨域。
比如我用的flask,可以自己写个装饰器添加允许跨域的请求头,也可以使用flask-cors库。

说点题外话,图片限制的话可以用’http://images.weserv.nl/?url=不带(https|http)://的图片地址‘ 进行替换(貌似可以穿墙)。

非简单请求

然而在可以成功跨域后,我又遇到了第二个问题(ff没有这个提示)。

Authorization不在preflight response的Access-Control-Allow-Headers中。
查看请求会发现只有一个options请求,这个就是preflight response——预检请求了。
简单的说,非简单请求就会产生预检请求来判断后端是否允许这条请求,而简单请求不会产生预检请求。

(来自参考3)

某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:

    使用下列方法之一:
        GET
        HEAD
        POST
        Content-Type :
             //注:仅当POST方法的Content-Type值等于下列之一才算作简单请求
               text/plain
               multipart/form-data
               application/x-www-form-urlencoded
    Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。该集合为:
        Accept
        Accept-Language
        Content-Language
        Content-Type (需要注意额外的限制)
        DPR
        Downlink
        Save-Data
        Viewport-Width
        Width

由于我在请求数据的时候用jwt验证,所以加入了Authorization这个header,所以就变成了非简单请求,需要在后端加入允许Authorization这个header。
加入以后就可以成功发送get请求了。

参考

  1. 【原创】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
  2. 跨域资源共享 CORS 详解
  3. HTTP访问控制(CORS)
0%