# 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、使用下列方法
GETHEADPOST
- 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即可代理。