跨域

作者: dsying | 来源:发表于2018-12-13 11:56 被阅读0次

    首先准备三个文件


    image.png

    server1.js

    const http = require('http')
    const fs = require('fs')
    const { resolve } = require('path')
    
    const app = http.createServer((req,res) => {
      const html = fs.readFileSync(resolve(__dirname,'./test.html'),'utf8')
      res.writeHead(200,{
        'Content-type': 'text/html'
      })
      res.end(html)
    })
    app.listen(8888)
    

    test.html

    <div>跨域测试</div>
    

    JSONP

    原理

    利用script标签的src不受浏览器同源策略约束的特性,发送跨域请求

    在test.html的</body> 标签上 添加一个script标签

      <div>跨域测试</div>
      <script>
          function cb() {
            console.log(arguments)
          } 
      </script>
      <script src="http://127.0.0.1:8887?callback=cb"></script>
    

    server2.js

    const http = require('http')
    const queryString = require('querystring')
    const url = require('url')
    
    const app = http.createServer((req, res) => {
        const qs = req.url.substring(req.url.lastIndexOf('?') + 1)
        const cb = queryString.parse(qs)
        const fn = cb.callback
        const callback = fn + '(' + '123' + ')'
        res.end(callback) 
    })
    app.listen(8887)
    

    CORS跨域资源共享

    XMLHttpRequest和Fetch API遵循同源策略,这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非使用CORS头文件
    注意:跨域请求可以正常发起,服务器也会接收并返回数据,但是浏览器会将返回的数据拦截

    原理

    通过设置response的响应头 Access-Control-Allow-Origin 来允许特定的访问
    test.html

    <script>
        // 利用 服务器端 response的 响应头 Access-Control-Allow-Origin: '*'
        var xhr = new XMLHttpRequest()
        xhr.open('GET','http://127.0.0.1:8887/')
        xhr.send() 
    </script>
    

    server2.js

    const http = require('http')
    
    const app = http.createServer((req, res) => {
      console.log('request2 come', req.url);
            res.writeHead(200,{
              // * 代表允许任何访问,你也可以写死 http://127.0.0.1:8888
              'Access-Control-Allow-Origin': '*',
            }) 
        res.end('123')
    })
    app.listen(8887)
    

    跨域的限制

    跨域允许的方法:

    • get
    • head
    • post
      跨域允许的Content-Type:
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
      请求头显示
    • 跨域时有些自定义请求头不被允许

    下面我们来测试下,注意html页面中 fetch请求的 method 和 headers
    test.html

      <script>
        fetch('http://127.0.0.1:8887',{
          method: 'PUT',
          headers: {
            'X-Test-Cors': '123'
          }
        })
      </script>
    
    const http = require('http')
    
    const app = http.createServer((req, res) => {
        res.writeHead(200,{
          'Access-Control-Allow-Origin': '*',
          // 'Access-Control-Allow-Headers': 'X-Test-Cors',
          // 'Access-Control-Allow-Methods': 'Put,Delete'
        }) 
        res.end('123')
    })
    app.listen(8887)
    

    控制台 network信息


    image.png

    浏览器报错信息


    image.png

    原因是什么呢?
    跨域请求时,put方法和自定义请求头X-Test-Cors是不被允许的,会触发
    CORS预检请求

    CORS预检请求

    跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。

    将server2.js修改一下

    const http = require('http')
    
    const app = http.createServer((req, res) => {
        res.writeHead(200,{
          'Access-Control-Allow-Origin': '*',
          //服务器允许的自定义的请求首部字段
          'Access-Control-Allow-Headers': 'X-Test-Cors',
          //服务器允许的请求方法
          'Access-Control-Allow-Methods': 'PUT,DELETE,OPTIONS'
        }) 
        res.end('123')
    })
    app.listen(8887)
    

    方法为options的 预检请求


    image.png

    方法为 put的真实请求


    image.png

    可以看到server2.js中我们设置了

          //服务器允许的自定义的请求首部字段
          'Access-Control-Allow-Headers': 'X-Test-Cors',
          //服务器允许的请求方法
          'Access-Control-Allow-Methods': 'PUT,DELETE,OPTIONS'
    

    Access-Control-Allow-Headers: 能够使自定义请求头 通过预检
    Access-Control-Allow-Methods:能够使指定方法 通过预检

    什么情况下会触发 预检请求

    “需预检的请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响

    当请求满足下述任一条件时,即应首先发送预检请求:

    • 使用了下面任一 HTTP 方法:
    • 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:
      • Accept
      • Accept-Language
      • Content-Language
      • Content-Type (but note the additional requirements below)
      • [DPR](http://httpwg.org/http-extensions/client-hints.html#dpr)
      • [Downlink](http://httpwg.org/http-extensions/client-hints.html#downlink)
      • [Save-Data](http://httpwg.org/http-extensions/client-hints.html#save-data)
      • [Viewport-Width](http://httpwg.org/http-extensions/client-hints.html#viewport-width)
      • [Width](http://httpwg.org/http-extensions/client-hints.html#width)
    • Content-Type 的值不属于下列之一:
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain
    • 请求中的XMLHttpRequestUpload 对象注册了任意多个事件监听器。
    • 请求中使用了ReadableStream对象。

    相关文章

      网友评论

          本文标题:跨域

          本文链接:https://www.haomeiwen.com/subject/ourvhqtx.html