浏览器同源策略与如何解决跨域问题总结

什么是同源策略

跨域问题实际就是浏览器的同源策略造成的。

同源策略限制了从同一个源加载的文档或脚本如何与另一个源的资源进行交互。这是浏览器的一个用于隔离潜在恶意文件的重要安全机制。同源指的是: 协议端口号域名必须一致。

下表给出了与 URL http://store.company.com/dir/page.html 的源进⾏对⽐的示例:
浏览器同源策略与如何解决跨域问题总结_第1张图片
同源策略:protocol(协议)、domain(域名)、port(端口)三者必须一致

同源策略主要限制了三个方面:

  • 当前域下的 js 脚本不能够访问其他域下的 cookie、localStorage 和 indexDB
  • 当前域下的 js 脚本不能够操作访问操作其他域下的 DOM。
  • 当前域下ajax无法发送跨域请求

同源政策的⽬的主要是为了保证⽤户的信息安全,它只是对 js 脚本的⼀种限制,并不是对浏览器的限制,对于⼀般的img、或者script脚本请求都不会有跨域的限制,这是因为这些操作都不会通过响应结果来进⾏可能出现安全问题的操作。

如何解决跨域问题

(1) CORS

下⾯是MDN对于CORS的定义:

跨域资源共享(CORS) 是⼀种机制,它使⽤额外的 HTTP 头来告诉浏览器 让运⾏在⼀个 origin(domain)上的Web应⽤被准许访问来⾃不同源服务器上的指定的资源。当⼀个资源从与该资源本身所在的服务器不同的域、协议或端⼝请求⼀个资源时,资源会发起⼀个跨域HTTP 请求。

CORS需要浏览器服务器同时⽀持,整个CORS过程都是浏览器完成的,⽆需⽤户参与。因此实现CORS的关键就是服务器,只要服务器实现了CORS请求,就可以跨源通信了。

浏览器将CORS分为简单请求⾮简单请求:

简单请求不会触发CORS预检请求。若该请求满⾜以下两个条件,就可以看作是简单请求:

1)请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

2)HTTP的头信息不超出以下⼏种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
    若不满足以上条件,就属于非简单请求了

简单请求过程:

对于简单请求,浏览器会直接发出CORS请求,它会在请求的头信息中增加⼀个Orign字段,该字段⽤来说明本次请求来⾃哪个源(协议+端⼝+域名),服务器会根据这个值来决定是否同意这次请求。如果Orign指定的域名在许可范围之内,服务器返回的响应就会多出以下信息头:

Access-Control-Allow-Origin: http://api.bob.com // 和Orign⼀直
Access-Control-Allow-Credentials: true // 表示是否允许发送Cookie
Access-Control-Expose-Headers: FooBar // 指定返回其他字段的值
Content-Type: text/html; charset=utf-8 // 表示⽂档类型

如果Orign指定的域名不在许可范围之内,服务器会返回⼀个正常的HTTP回应,浏览器发现没有上⾯的Access-Control-Allow-Origin头部信息,就知道出错了。这个错误⽆法通过状态码识别,因为返回的状态码可能是200。

在简单请求中,在服务器内,⾄少需要设置字段: Access-Control-Allow-Origin

非简单请求过程:

⾮简单请求是对服务器有特殊要求的请求,⽐如请求⽅法为DELETE或者PUT等。⾮简单请求的CORS请求会在正式通信之前进⾏⼀次HTTP查询请求,称为预检请求

浏览器会询问服务器,当前所在的⽹⻚是否在服务器允许访问的范围内,以及可以使⽤哪些HTTP请求⽅式和头信息字段,只有得到肯定的回复,才会进⾏正式的HTTP请求,否则就会报错。

预检请求使⽤的请求⽅法是OPTIONS,表示这个请求是来询问的。他的头信息中的关键字段是Orign,表示请求来⾃哪个源。除此之外,头信息中还包括两个字段:

  • Access-Control-Request-Method:该字段是必须的,⽤来列出浏览器的CORS请求会⽤到哪些HTTP⽅法。
  • Access-Control-Request-Headers: 该字段是⼀个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。

服务器在收到浏览器的预检请求之后,会根据头信息的三个字段来进⾏判断,如果返回的头信息在中有Access-Control-Allow-Origin这个字段就是允许跨域请求,如果没有,就是不同意这个预检请求,就会报错。

服务器回应的CORS的字段如下:

Access-Control-Allow-Origin: http://api.bob.com // 允许跨域的源地址
Access-Control-Allow-Methods: GET, POST, PUT // 服务器⽀持的所有跨域请求的⽅法
Access-Control-Allow-Headers: X-Custom-Header // 服务器⽀持的所有头信息字段
Access-Control-Allow-Credentials: true // 表示是否允许发送Cookie
Access-Control-Max-Age: 1728000 // ⽤来指定本次预检请求的有效期,单位为秒

只要服务器通过了预检请求,在以后每次的CORS请求都会⾃带⼀个Origin头信息字段。服务器的回应,也都会有⼀个Access-Control-Allow-Origin头信息字段。

在⾮简单请求中,⾄少需要设置以下字段:

'Access-Control-Allow-Origin'
'Access-Control-Allow-Methods'
'Access-Control-Allow-Headers'

减少OPTIONS请求次数:
OPTIONS请求次数过多就会损耗⻚⾯加载的性能,降低⽤户体验度。所以尽量要减少OPTIONS请求次数,可以后端在请求的返回头部添加:Access-Control-Max-Age:number。它表示预检请求的返回结果可以被缓存多久,单位是秒。该字段只对完全⼀样的URL的缓存设置⽣效,所以设置了缓存时间,在这个时间范围内,再次发送请求就不需要进⾏预检请求了

CORS中Cookie相关问题:
在CORS请求中,如果想要传递Cookie,就要满⾜以下三个条件:

  • 在请求中设置 withCredentials

默认情况下在跨域请求,浏览器是不带 cookie 的。但是我们可以通过设置 withCredentials 来进⾏传递 cookie

// 原⽣ xml 的设置⽅式
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
// axios 设置⽅式
axios.defaults.withCredentials = true;
  • Access-Control-Allow-Credentials 设置为 true
  • Access-Control-Allow-Origin 设置为false

(2) JSONP

jsonp的原理就是利⽤

你可能感兴趣的:(浏览器,前端,http,服务器)