什么是跨域
跨域是由于浏览器的同源策略,为了防范跨站脚本的攻击,禁止客户端对不同域下的文档或脚本进行跨站调用资源。
相反,同源就是指协议、域名、端口号相同。
同源是浏览器的安全功能,如果没有这个安全策略,浏览器很容易受到XSS、CSFR攻击。
跨域的解决方案
vue开发环境配置
在vue.config.js中配置如下
module.exports = {
pages: {
index: {
//入口
entry: 'src/main.js',
},
},
lintOnSave:false, //关闭语法检查
//开启代理服务器(方式一) 只能开启一个服务
/* devServer: {
proxy: 'http://localhost:5000'
}, */
//开启代理服务器(方式二) 可以配置多个服务
devServer: {
proxy: {
'/api1': {
target: 'http://localhost:5000',
pathRewrite:{'^/api1':''},
// ws: true, //用于支持websocket
// changeOrigin: true //用于控制请求头中的host值
},
'/api2': {
target: 'http://localhost:5001',
pathRewrite:{'^/api2':''},
// ws: true, //用于支持websocket
// changeOrigin: true //用于控制请求头中的host值
}
}
}
}
缺点:上述方法只能在开发中使用,需要前端自己配置
JSONP
这是比较早的解决方案,script标签的src、img的标签的src、link标签的href没有被同源策略所限制。
原理:
- 客户端利用script标签的src属性,去请求一个接口,因为src不受跨域影响
- 服务端响应一个字符串
- 客户端收到字符串,然后把它当做JS代码允许
缺点:
- jsonp只能使用GET方式
- 调用失败的时候不能返回任何状态码,不利于调试
- 安全性较差。jsonp提供的网站会存在页面注入漏洞,即它返回的JavaScript内容被人为的控制。因此使用jsonp的时候必须保证使用的jsonp服务必须是安全可信的。
CORS
CORS是一个W3C标准,全称是“跨域资源共享”,它允许浏览器向跨域服务器发送请求,从而克服了AJAX只能同源使用的限制。前端不需要配置,而后端则需要开启CROS。
但是CORS也有缺点:IE版本不能低于10
浏览器将CORS请求分为两类简单请求和非简单请求
简单请求
-
请求方法是以下三种方法之一
- HEAD
- GET
- POST
-
HTTP的头信息不超出以下几种字段
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于
application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器之间发送CORS请求,就是在头信息中,增加一个Origin字段,用来说明本次请求来自哪个源,服务器根据这个值,决定是否同意这次请求。
Orgin中会指出当前请求属于哪个域(协议+域名+端口)。服务会根据这个值决定是否允许其跨域。
如果服务器允许跨域,需要在返回的响应头中携带下面信息:
- Access-Control-Allow-Origin 必选,表示接受哪些域名的请求
- Access-Control-Allow-Credentials 可选,表示是否发送cookie(默认为false,不携带)
- Access-Control-Expose-Headders 可选,XHMttpRequest对象的方法只能拿到六种字段
Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果想拿到其他的需要使用该字段指定。
非简单请求
不满足简单请求的就是非简单请求,比如PUT请求,或请求头包含其它字段。
非简单请求的CORS请求是会在正式通信之前进行一次预检请求:浏览器会先询问服务器,当前网页所在的域名是否可以请求您的服务器,如果得到正确的答复,才会进行正式的请求。
若发出如下的预检请求:
OPTIONS /cors HTTP/1.1
Origin: https://baidu.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: baidu.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
预检请求:
- Access-Control-Request-Method:用到的请求方式
- Access-Control-Request-Headers:会额外用到的头信息
服务端收到预检请求之后,如果许可跨域,会发出响应:
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://baidu.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
响应:
- Access-Control-Allow-Method:允许访问的方式
- Access-Control-Allow-Headers:允许携带的头
- Access-Control-Max-Age:本次许可的有效时长,单位是秒,过期之前的AJAX请求就无需再次进行预检了
如果浏览器得到以上响应,则认为可以跨域。
以上是三种常见的跨域解决方案,喜欢的可以点个赞~