跨域

首先准备三个文件


跨域_第1张图片
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

跨域测试

JSONP

原理

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

在test.html的 标签上 添加一个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


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

  
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信息


跨域_第2张图片
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的 预检请求


跨域_第3张图片
image.png

方法为 put的真实请求


跨域_第4张图片
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 方法:
    • PUT
    • DELETE
    • CONNECT
    • OPTIONS
    • TRACE
    • PATCH
  • 人为设置了对 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对象。

你可能感兴趣的:(跨域)