三种跨域解决方案

413 阅读4分钟

什么是跨域


跨域是由于浏览器的同源策略,为了防范跨站脚本的攻击,禁止客户端对不同域下的文档或脚本进行跨站调用资源。

相反,同源就是指协议、域名、端口号相同。

同源是浏览器的安全功能,如果没有这个安全策略,浏览器很容易受到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请求分为两类简单请求非简单请求

简单请求

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

    • HEAD
    • GET
    • POST
  2. HTTP的头信息不超出以下几种字段

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于 application/x-www-form-urlencodedmultipart/form-datatext/plain

对于简单请求,浏览器之间发送CORS请求,就是在头信息中,增加一个Origin字段,用来说明本次请求来自哪个源,服务器根据这个值,决定是否同意这次请求。

Orgin中会指出当前请求属于哪个域(协议+域名+端口)。服务会根据这个值决定是否允许其跨域。

如果服务器允许跨域,需要在返回的响应头中携带下面信息:

  • Access-Control-Allow-Origin 必选,表示接受哪些域名的请求
  • Access-Control-Allow-Credentials 可选,表示是否发送cookie(默认为false,不携带)
  • Access-Control-Expose-Headders 可选,XHMttpRequest对象的方法只能拿到六种字段 Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma ,如果想拿到其他的需要使用该字段指定。

非简单请求

不满足简单请求的就是非简单请求,比如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请求就无需再次进行预检了

如果浏览器得到以上响应,则认为可以跨域。


以上是三种常见的跨域解决方案,喜欢的可以点个赞~