跨域

2018-12-13  本文已影响0人  dsying

首先准备三个文件


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)

跨域的限制

跨域允许的方法:

下面我们来测试下,注意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 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响

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

上一篇 下一篇

猜你喜欢

热点阅读