前端跨域解决方案之CORS详解

03-15 阅读 0评论

前端跨域解决方案之CORS详解

一、介绍

CORS 是一个 W3C 标准,全称是“跨源资源共享”(Cross-origin resource sharing),或者通俗地

前端跨域解决方案之CORS详解,前端跨域解决方案之CORS详解,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,方法,第2张
(图片来源网络,侵删)

称为“跨域资源共享”。它允许浏览器向跨源的服务器,发出XMLHttpRequest请求,从而克服AJAX

只能同源使用的限制。

二、为什么会出现跨域问题

为了保证用户信息的安全,所有的浏览器都遵循同源策略。

所谓同源是指"协议+域名+端口"三者都相同,有任何一个不同时,浏览器都视为非同源。

当你向非同源的服务器发起网络请求的时候,这个请求就是跨域了。

举例来说,http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略),dir/page.html是请求资源。它的同源情况:

前端跨域解决方案之CORS详解,前端跨域解决方案之CORS详解,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,方法,第3张
(图片来源网络,侵删)
  • http://www.example.com/dir2/other.html:同源(同一域名)
  • http://example.com/dir/other.html:不同源(域名不同)
  • http://v2.www.example.com/dir/other.html:不同源(域名不同)
  • http://www.example.com:81/dir/other.html:不同源(端口不同)
  • https://www.example.com/dir/page.html:不同源(协议不同)

    注:我们在使用postman等工具模拟发起http请求的时候,不会遇到跨域的情况。

    三、两种请求

    浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。浏览器对这两种请求的处理是不一样的。

    只要同时满足以下两大条件,就属于简单请求。否则属于非简单请求。

    (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

        1、简单请求

        当浏览器判定某个跨域请求是简单请求时,会在请求头信息之中,自动增加一个Origin字段。

        前端跨域解决方案之CORS详解,前端跨域解决方案之CORS详解,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,方法,第4张
        (图片来源网络,侵删)
        GET /cors HTTP/1.1
        Origin: http://api.bob.com
        Host: api.alice.com
        Accept-Language: en-US
        Connection: keep-alive
        User-Agent: Mozilla/5.0...

        上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

        如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

        如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。

        Access-Control-Allow-Origin: http://api.bob.com
        Access-Control-Allow-Credentials: true
        Access-Control-Expose-Headers: FooBar
        Content-Type: text/html; charset=utf-8

        ·Access-Control-Allow-Origin

        该字段是必须的。它的值要么是请求时Origin字段值,要么是一个*,表示接受任意域名的请求。

        2、非简单请求

        非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

        非简单请求会在正式通信之前,增加一次HTTP查询请求,称为“预检”请求(preflight)。

        浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

        2.1 预检请求

        下面是这个“预检”请求的HTTP头信息。

        OPTIONS /cors HTTP/1.1
        Origin: http://api.bob.com
        Access-Control-Request-Method: PUT
        Access-Control-Request-Headers: X-Custom-Header
        Host: api.alice.com
        Accept-Language: en-US
        Connection: keep-alive
        User-Agent: Mozilla/5.0...

        “预检”请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。

        除了Origin字段,“预检”请求的头信息包括两个特殊字段。

        (1)Access-Control-Request-Method

        该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。

        (2)Access-Control-Request-Headers

        该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。

        2.2 预检请求的回应

        服务器收到“预检”请求以后,检查了Origin、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://api.bob.com
        Access-Control-Allow-Methods: GET, POST, PUT
        Access-Control-Allow-Headers: X-Custom-Header
        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

        上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。

        Access-Control-Allow-Origin: *

        如果服务器否定了“预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

        XMLHttpRequest cannot load http://api.alice.com.
        Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

        一旦服务器通过了“预检”请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

        四、跨域解决方案

        (1)后端那边帮忙加上了一個 header:Access-Control-Allow-Origin: *,代表來自任何 origin 的网站都可以用 AJAX 存取這個資源。

        后端代码如下:

        app.get('/', (req, res) => {
          res.header('Access-Control-Allow-Origin', '*')
          res.json({
            data: db.getFormOptions(),
          })
        })

        更多情况:CORS 完全手冊(三):CORS 詳解 - Huli's blog

         

        (2)Vue脚手架Vue-Cli3.x 使用proxy代理方案

        浏览器是禁止跨域的,但是服务端不禁止,在本地运行npm run dev等命令时实际上是用node运行了一个webpack开发服务器,因此proxyTable实际上是将请求发给自己的服务器,再由服务器转发给后台服务器,亦做了代理转发,因此不会出现跨域问题。

        可以在根目录下建立一个vue.config.js的文件:

        module.exports = {
          devServer: {
            // https://www.baidu.com/company/getall
            proxy: {    // 配置跨域
              '/api': {    // 请求相对路径以/api开头的, 才会走这里的配置
                target: 'https://www.baidu.com/',    // 需要代理的地址
                secure: false,    // 如果是不是https接口,可以不配置这个参数
                changeOrigin: true,    // 允许跨域
                pathRewrite: {
                  '^/api': '', // 路径重写,将前缀/apis转为"/",也可以理解为"/apis"代替target里面的地址
                  // 如果本身的接口地址就有"/api"这种通用前缀,也就是说https://www.exaple.com/api,就可以把pathRewrite删掉,如果没有则加上
                },
              },
            },
          },
        };
        

        axios请求的代码:

        axios({
            url: '/api/company/getall'
        })

        参考:

        JavaScript CORS通信_w3cschool


免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,人围观)

还没有评论,来说两句吧...

目录[+]