# 36、9跨域方法
# 跨域
浏览器是不支持跨域的,包括
cookie,localStorage,DOM
元素也有同源策略,在客户端我们通常使用ajax
来向服务器端发送请求,从而获取到服务器返回的数据结果;但是ajax
有局限性:
ajax
是同源策略请求:不允许跨域访问
# 同源与非同源
TIP
拿当前页面的地址和 数据请求的接口地址(即AJAX
中URL
设定的地址) 作比较;
如果下面三个都相同,那么就是同源策略,只要有一个不一样就是非同源(即跨域访问)
- 1、协议一致
- 2、域名或者
ip
一致(只能是域名对域名,IP对IP) - 3、端口号一致
同源策略限制的内容:
- 1、Cookie、LocalStorage、IndexedDB等存储性内容
- 2、DOM节点
- 3、AJAX请求发送后,返回结果被浏览器拦截
为什么会出现跨域请求: 在项目的前后端分离中,会出现跨域的问题
- 1、前后端同时开发,前端和后端都会把自己开发的项目部署到不同的站点上(或者不同的服务器上,减轻服务器的请求压力),此时就是跨域请求
- 2、本地开发的时候,预览页面一般都是
localhost
域名,而接口地址一般都是一个真实的域名,此时开发的时候想要调取服务器数据,也是跨域请求;
# 跨域解决方案
# 基于JSONP实现跨域请求:
方案一
JSONP
原理:利用script/img/link
不存在跨域问题
缺点
- 1、
JSONP
需要服务器端支持(如果服务器端不支持JSONP
处理,我们无法使用) - 2、
JSONP
不安全(不能防止XSS
攻击),如果服务器支持,任何网站都可以获取我们的数据(一般公用接口可以用它来实现,但是重要信息,不建议使用) - 3、
JSONP
都是get
请求(没有POST,PUT,DELETE
请求,不能处理大数据传输:尤其是客户端想把大数据发送给服务器端)
# CORS跨域资源共享
CORS
CORS
的基本思想,就是使用 自定义的HTTP
头部让浏览器与服务器进行沟通,从而决定请求或者响应是应该成功还是应该失败
浏览器会自动进行CORS
通信,实现CORS
通信的关键是后端。服务端设置Access-Control-Allow-Origin
就可以开启CORS
。该属性表示哪些域名可以访问资源。设置为通配符则表示所有网站都可以访问资源。
CORS
虽然和前端没关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为 简单请求
和 复杂请求
简单请求 满足以下两大条件,就属于简单请求
- 1、使用下列方法
GET
HEAD
POST
- 2、请求头
Content-Type
的值仅限于下列三者之一text/plain
:纯文本格式,在发送时浏览器不会对其做处理multipart/form-data
:常用于文件等二进制,也可用于键值对参数,最后连接成一串字符传输application/x-www-form-urlencoded
:浏览器默认编码格式,会对参数进行编码,转换为key=value
的形式,多个用&
号隔开,get
请求追加到url
末尾,post
请求会放入请求主体中发送给后端。
复杂请求
不满足上述条件就是复杂请求。复杂的CORS
请求,会在正式通信之前,发出一个预检请求(options
请求),通过该请求来知道服务端是否允许跨域。
优化预检请求
res.setHeader("Access-Control-Max-Age",60)
设置了这个响应头之后,在60秒之内,同类型的请求都将不再发送预检请求,而是使用之前返回的Access-Control-Allow-Methods
和Access-Control-Allow-Headers
提供的结果
以node.js
作为后台的跨域头(express
框架)
app.all('*', function(req, res, next) {
//哪个源可以访问我
res.setHeader("Access-Control-Allow-Origin", "*");
//允许携带哪个自定义头访问我,多个自定义头用指尖用逗号隔开
res.setHeader("Access-Control-Allow-Headers", "ticket,name");
//允许哪种请求方法访问我
res.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
//允许携带cookie
res.setHeader("Access-Control-Allow-Credentials",true)
//预检请求的存活时间,单位为s(多久之内不再发送预检请求)如果值为 -1,则表示禁用缓存,每一次请求都需要提供预检请求,即用OPTIONS请求进行检测。
res.setHeader("Access-Control-Max-Age",60) // options预检请求的优化
//允许返回的头
res.setHeader("Access-Control-Expose-Headers","name")
//这段仅仅为了方便返回json而已
res.setHeader("Content-Type", "application/json;charset=utf-8");
if(req.method == 'OPTIONS') {
//让options请求快速返回
res.sendStatus(200);
} else {
next();
}
});
常见CORS
跨域错误
- 1、
The response had HTTP status code 404``options
请求过不去:后端没有支持options
请求,需要后端值支持 - 2、
The response had HTTP status code 405``options
请求过不去:后端支持options
请求,但是一些配置文件(如安全配置)中,阻止了options
请求。需要安全配置支持options
请求。 - 3、
options
请求返回200
,但是浏览器报错:origin
不匹配或者headers
不匹配,缺少值。
# 3、webSocket(没有域的)
let ws = new WebSocket('wx://localhost:3000');
ws.onopen = function(){
ws.send('我爱你')
}
wx.onmessage = function(e){
console.log(e.data)
}
# 4、nginx反向代理
nginx
利用同源策略对服务器不加限制的原理,使用nginx
反向代理实现跨域,是最简单的跨域方式。只需要修改nginx
的配置即可解决跨域问题,支持所有浏览器,支持session
,不需要修改代码,并且不会影响服务器性能。
实现思路:通过nginx
配置一个代理服务器(域名与domain1
相同,端口不同)做跳板机,反向代理访问domain2
接口,并且可以顺便修改cookie
中domain
信息,方便当前域cookie
写入,实现跨域登录。
# 5、代理解决跨域问题
TIP
开发中常用的proxy
代理解决跨域问题,原理是当我们启动项目的时候,webpack
内部会用http-proxy-middleware
中间件,以我们本机为服务器起一个服务,监听请求的端口。项目发起请求时,请求的是本地的接口,本地接口收到请求后,向实际的接口请求数据,然后再将信息返回给前端。一般都用node.js
即可代理。