Skip to content

Latest commit

 

History

History
138 lines (122 loc) · 5.78 KB

5.md

File metadata and controls

138 lines (122 loc) · 5.78 KB

关于跨域请求的其他限制

  • 并不是所有情况的跨域都可以设置Access-Control-Allow-Origin
  • 我们还是通过例子来说明

自定义的头信息

1 ) 准备程序

  • server1.js

    const http = require('http');
    const fs = require('fs');
    
    http.createServer((req, res) => {
        console.log('req come: ', req.url);
        const html = fs.readFileSync('test.html', 'utf8');
        // 默认是下面这个writeHead设置,不写也可以
        res.writeHead(200, {
        'Content-Type': 'text/html'
        });
        res.end(html);
    }).listen(8000, () => {
        console.log('server is running on port 8000');
    });
  • server2.js

    const http = require('http');
    
    http.createServer((req, res) => {
        console.log('req come: ', req.url);
        // 在writeHead时候添加跨域支持
        res.writeHead(200, {
            'Access-Control-Allow-Origin': '*'
        });
        res.end('req come: ' + req.url);
    }).listen(8001, () => {
        console.log('server is running on port 8001');
    });
  • test.html

    <script>
        fetch('http:https://localhost:8001', {
            method: 'POST',
            headers: {
                'X-Test-Cors': '123'
            }
        });
    </script>

2 ) 启动两个程序

3 ) 出现问题

  • 检查页面节点,已经正常加载
  • 浏览器debug后,发现报错了
  • 此时就会报错
    Access to fetch at 'http:https://localhost:8001/' from origin 'http:https://localhost:8000' has been blocked by CORS policy: Request header field x-test-cors is not allowed by Access-Control-Allow-Headers in preflight response.
    

4 ) 问题分析

  • 4.1 ) 上面报错信息是说,我们自己加上这个头信息X-Test-Cors在跨域请求中是不被允许的
  • 注意,一定要注意是在跨域请求中,如果是同域请求是被允许的,这就属于CORS预请求所研究的范畴了
  • 具体的请求头限制可以参考:https://fetch.spec.whatwg.org/#cors-safelisted-request-header
  • 4.2 ) 而在跨域的时候默认允许的方法只有三种:GET、POST、HEAD这三种
  • 其他方法都是不被允许的,浏览器会用预请求的方式来验证
  • 4.3 ) 同时允许的Content-Type也有限制,只允许:text/plain、multipart/form-data、application/x-www-form-urlencoded这三种
  • 其他的Content-Type同样也需要验证
  • 4.4 ) 其他限制
    • 4.41 ) XMLHttpRequestUpload对象均没有注册任何事件监听器
    • 4.42 ) 请求中没有使用ReadableStream对象
    • 上面这两个很少会被用到

5 ) 关于预请求与解决方案

  • 浏览器是根据什么来判断请求是否被允许呢?这就是根据header来判断
  • 如果程序需要添加头信息,服务端在响应的时候需要返回一个头告诉浏览器这个头是被允许的
  • 所以这时候,我们只需要添加
    res.writeHead(200, {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': 'X-Test-Cors' // 新添加这行
    });
  • 添加之后,就可以正确接收了, 但是我们可以发现, 比刚才多了一个OPTIONS请求, 这个就是预请求
  • 通过OPTIONS请求来获得服务端允许的认可, 然后再次发送POST请求
  • 这就是浏览器对于跨域请求预请求的一个操作
  • 注意,如果之前test.html中的fetch函数用的是GET,同样会发送两个请求,一个是OPTIONS,一个是GET
  • 什么时候需要预请求呢?一般自定义的请求需要进行预请求来进行验证,此处不再展开
  • 注意,OPTIONS不是POST请求的专属,一般的GET,POST是没有必要进行OPTIONS请求的
  • 同样,也不是使用fetch这个api的原因,就是单纯的HTTP规则
  • 注意,如果使用没有定义的方法,如PUT来请求,如下
    <script>
        fetch('http:https://localhost:8001', {
            method: 'PUT'
        });
    </script>
  • 会出现问题
    Access to fetch at 'http:https://localhost:8001/' from origin 'http:https://localhost:8000' has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.
    
  • 这个问题说明当前不被允许,所以,这个问题需要解决
  • 我们想要实现RESTful API的时候,需要添加语义化的请求方法,如:PUT,DELETE,PATCH等
  • 这个时候,我们需要添加对各类方法的支持,注意GET,POST,OPTIONS不必添加,默认支持
    res.writeHead(200, {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': 'X-Test-Cors',
        'Access-Control-Allow-Methods': 'PUT, DELETE, PATCH' // 新添加这行,一般GET,POST,OPTIONS不必添加,默认支持
    });
  • 添加支持后,同样,我们可以看到有两次请求,一个是OPTIONS请求,一个是新添加的请求方法
  • 注意,如果你用其他未支持的方法,比如自定义的字符来作为请求方法的话,如定义一个字符串或字符'X'作为请求方法
  • 那么这时候即使服务端添加了对'X'方法的支持,结果仍只有一个OPTIONS预请求,最终依然无法通过
  • 因为这已经超越规则了,不被HTTP协议所允许
  • 浏览器通过这种机制来保证跨域访问的安全性
  • 关于预请求,还有一个常用的设置Access-Control-Max-Age, 通过这个设置,浏览器可以在设置的时间内不会再次发送预请求
    res.writeHead(200, {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': 'X-Test-Cors',
        'Access-Control-Allow-Methods': 'PUT, DELETE, PATCH',
        'Access-Control-Max-Age': 1000 // 新添加这行, 1000s内不会再次发送预请求
    });