跨域的解决方法(续)
上篇文章中跨域的解决方案,我们简单的介绍了下跨域的原因以及使用postMessage解决跨域,这篇我们我们再来介绍几种前端跨域的解决方案
JSONP
JSON和JSONP虽然只有一个字母之差,但是它们却压根不是一回事:
JSON是一种数据交换格式,而JSONP是一种非官方的跨域数据交互协议。它们一个是描述信息的格式,一个是信息传递双方约定的方法。
JSONP的产生
上篇文章中说到过,ajax在调用跨域请求时,存在跨域无权限访问的情况,但是后来伟大的程序员又发现,Web页面上调用js文件不受跨域问题的影响。不仅如此,我们还发现凡是拥有src这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>)。
于是我们判断,当前阶段如果想要跨域访问数据时,我们可以把数据外面包裹上一层js代码,供客户端调用和统一处理。
为了方便客户端使用数据,逐渐形成了一种非正式的传输协议JSONP,该协议的一个要点就是允许用户传递一个callback给服务端,然后服务端返回数据时会将这个callback参数作为函数名包裹JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
JSONP的使用
1 | <script src="http://domain/api?param1=a¶m2=b&callback=jsonp"></script> |
JSONP使用简单而且兼容性不错,但是只限于get请求。
看过JSONP库源码的童靴想必知道,JSONP常见的代码实现其实就是document.createElement(‘script’)生成一个script标签,然后插入到body中而已。所以JSONP的实现原理就是创建一个scrip标签,然后再把需要请求的api地址放到scr里,这个请求只能是get方法,不可能是post方法。
跨域资源共享(CORS)
在出现跨域资源共享之前,我们只能通过JSONP来解决跨域问题。上面我们也说到过,JSONP只能支持GET请求,在前端日益复杂的今天,仅仅只靠JSONP怎么可能,所以这个时候,CORS应运而生了。
CORS原理
支持CORS的浏览器,一旦发现ajax在做跨域请求时,会进行一些特殊的处理,对于已经实现CORS接口的服务端,接收请求并做出回应。
浏览器对跨域请求进行了一个简单的区分–简单请求和非简单请求
简单请求
若一个请求同时满足以下条件,则将其视为简单请求。
- 使用的方法
- HEAD
- GET
- POST
- HTTP请求头信息为以下几种字段
- Accept
- Accept-Lanuage
- Content-Lanuage
- Last-Event-ID
- Content-Type:
application/x-www-form-urlencoded、 multipart/form-data、text/plain
当浏览器判断一个请求是简单请求后,会在Request Header中添加Origin(协议+域名+端口)字段,表示我们的请求源,CORS会将该字段作为跨域的标志。

CORS接收到此请求后,首先会判断origin是否在允许源(由服务端决定)范围之内,如果验证通过,服务端会在Response Header 添加 Access-Control-Allow-Origin、Access-Control-Allow-Credentials等字段。

浏览器收到Response后会判断自己是否在Access-Control-Allow-Origin允许源中,如果不存在,会抛出“同源检测异常”。
非简单请求
不满足以上两个条件的请求成为非简单请求。
对于非简单请求,浏览器首先发出类型为OPTIONS的预检请求,主请求和预检请求地址相同,CORS服务端对预检请求处理,并在Response Header中添加标识字段,客户端接收到预检请求的返回值进行一次预检请求的判断,如果判断通过则发起主请求。

这里我们可以看到,浏览器连续发送了两个请求,第一个就是预检请求,类型为OPTIONS,第二个请求才是我们发出的请求。
预检请求通过后,主请求开始发送。
所以,CORS的非简单请求只是在简单请求的基础上加了一个预检请求而已。
CORS的使用
CORS在前端的使用很简单,只需要在构建axios实例时加上一行代码
1 | axios.defaults.withCredentials = true |
要想完整的使用CORS解决跨域问题,还需要后端童靴的支持,可以说实现CORS的关键是后端,只要后端实现了CORS,就实现了跨域。
Vue2.0 proxyTable跨域
proxyTable是Vue-cli中的一种跨域方式,主要依赖的是http-proxy-middleware中间件。实现的原理也很简单,其本质是本地开了一个服务器dev-server(所以proxyTable只能在开发环境中使用),浏览器先将跨域请求发给自己的服务端,由自己的服务端再转发给要跨域的服务端,做一层代理来实现跨域。
proxyTable的使用
这里以Vue-cli3.0举例。在Vue-cli3.0中,webpack的配置主要写在vue.config.js中
1 | devServer: { |
然后在我们请求数据或者axios封装时,只需要使用’/cmdb’即可。
1 | axios.defaults.baseURL = '/cmdb' |
nginx代理跨域
上面我们说到的proxyTable只能够在开发环境下使用,那么我们在生产环境上怎么办呢? nginx反向代理无疑是一种很好的解决方案。
那么nginx的反向代理为什么能够实现跨域呢?
首先,我们直接在浏览器上输入地址,是不会产生跨域问题,只有在某域名页面,由该页面发起的接口请求才可能跨域。nginx就相当于这个浏览器,它接收到外部对它的请求(注意:nginx只会接收别人对它的请求,但是并不会拦截请求),在类似浏览器的地址栏中去请求某个接口,最后将请求的内容返回回去。
nginx 配置
nginx解决跨域需要配置url请求规则,主要配置信息都在nginx.conf文件中
1 | location /cmdb/ { |
nginx解决跨域问题在前端开发中也经常使用,因此需要重点掌握。
本文主要介绍了几种常见的前端跨域方法,当然跨域的方法远远不止这几种,感兴趣的同学可以参考前端常见跨域解决方案(全)