# 36、9跨域方法

# 跨域

浏览器是不支持跨域的,包括 cookie,localStorage,DOM元素也有同源策略,在客户端我们通常使用ajax来向服务器端发送请求,从而获取到服务器返回的数据结果;但是ajax有局限性:

ajax是同源策略请求:不允许跨域访问

# 同源与非同源

TIP

当前页面的地址数据请求的接口地址(即AJAXURL设定的地址) 作比较; 如果下面三个都相同,那么就是同源策略,只要有一个不一样就是非同源(即跨域访问)

  • 1、协议一致
  • 2、域名或者ip一致(只能是域名对域名,IP对IP)
  • 3、端口号一致

同源策略限制的内容:

  • 1、Cookie、LocalStorage、IndexedDB等存储性内容
  • 2、DOM节点
  • 3、AJAX请求发送后,返回结果被浏览器拦截

为什么会出现跨域请求: 在项目的前后端分离中,会出现跨域的问题

  • 1、前后端同时开发,前端和后端都会把自己开发的项目部署到不同的站点上(或者不同的服务器上,减轻服务器的请求压力),此时就是跨域请求
  • 2、本地开发的时候,预览页面一般都是localhost域名,而接口地址一般都是一个真实的域名,此时开发的时候想要调取服务器数据,也是跨域请求;

# 跨域解决方案

# 基于JSONP实现跨域请求:

方案一

JSONP原理:利用script/img/link不存在跨域问题 js-36-1

缺点

  • 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-MethodsAccess-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接口,并且可以顺便修改cookiedomain信息,方便当前域cookie写入,实现跨域登录。

# 5、代理解决跨域问题

TIP

开发中常用的proxy代理解决跨域问题,原理是当我们启动项目的时候,webpack内部会用http-proxy-middleware中间件,以我们本机为服务器起一个服务,监听请求的端口。项目发起请求时,请求的是本地的接口,本地接口收到请求后,向实际的接口请求数据,然后再将信息返回给前端。一般都用node.js即可代理。

上次更新: 6/11/2021, 7:40:47 PM