http协议(一)CORS跨域请求的限制与解决

1. 什么是跨域?

要了解什么是跨域,首先需要知道什么是同源策略。同源策略是由Netscape公司提出的一个注明的安全策略,所有支持JavaScript的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当页面执行一个脚本时会检查访问的资源是否同源,如果非同源,那么在请求数据时,浏览器就会在控制台中抱一个异常,提示拒绝访问。
同源策略一般又分为两种:
DOM同源策略:禁止对不同源页面DOM进行操作。这里主要场景是iframe跨域的情况,不同域名的iframe是限制互相访问的;
XmlHttpRequest同源策略:禁止使用XHR对象向不同源的服务器地址发起HTTP请求。
所以跨域是什么?
跨域,是指在请求一个不属于同源的资源时,这种行为就称为跨域,这是浏览器施加的安全限制。

2. 如何解决跨域请求

我们现在搭建两个web服务,一个监听本地8888端口,一个监听本地8887端口,8888端口返回一个html文件,该html文件中访问了8887端口:
server.js:

const http = require('http')
const fs = require('fs')

http.createServer(function (request, response){
  console.log('request url: ', request.url)
  const html = fs.readFileSync('index.html', 'utf-8')
  response.writeHead(200, {
    'Content-Type': 'text/html'
  })
  response.end(html)
}).listen(8888)

console.log('server running on 8888')

server2.js:

const http = require('http')

http.createServer(function (request,response){
  console.log('request url: ', request.url)
  response.end('123')
}).listen(8887)

console.log('server running on 8887')

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <div>content</div>
</body>
<script>
  var xhr = new XMLHttpRequest()
  xhr.open('GET', 'http://127.0.0.1:8887/')
  xhr.send()
</script>
</html>

使用node server.jsnode server2.js开启Web服务,访问8888端口:
在这里插入图片描述
我们发现控制台报错:
在这里插入图片描述
这里的异常信息是说,访问8887返回的数据被跨域策略阻止了,因为响应头中没有设置Access-Control-Allow-Origin
我们现在修改server2.js,向返回数据的响应头添加相应内容:

const http = require('http')

http.createServer(function (request,response){
  console.log('request url: ', request.url)
  // 添加以下内容
  response.writeHead(200, {
    'Access-Control-Allow-Origin': '*'
  })
  response.end('123')
}).listen(8887)

console.log('server running on 8887')

重新运行node server2.js,然后刷新127.0.0.1:8888,我们发现控制台没有报错信息了,并且我们从8887拿到了正确的返回信息:
在这里插入图片描述
现在,我们访问8887端口返回的数据响应头中多出来了'Access-Control-Allow-Origin': '*',正是因为有了这一个说明,才能使浏览器接收8887返回的数据。

3. 网络请求从发起到返回

如果我们没有设置'Access-Control-Allow-Origin': '*',浏览器会报错,我们拿不到8887端口返回的内容,但是,这是否说明是8887端口拒绝了我们的访问呢?

其实,即使我们不做任何设置,只要向8887发起请求,8887就会返回其应该返回的内容(这里8887需要返回‘123’),同时,浏览器也能获取到这个返回数据,当浏览器收到这个返回数据时,浏览器会检查这个数据和当前页面是否同源,如果不符合同源策略,浏览器就会舍弃这个数据。

当我们为返回数据设置了'Access-Control-Allow-Origin': '*'之后,浏览器在对资源进行同源判定时,就会根据这个信息来判断资源是否和当前页面同源。

如果我们修改server2.js:

const http = require('http')

http.createServer(function (request,response){
  console.log('request url: ', request.url)
  response.writeHead(200, {
    'Access-Control-Allow-Origin': 'http://127.0.0.1:8886'
  })
  response.end('123')
}).listen(8887)

console.log('server running on 8887')

然后访问127.0.0.1:8888,这时候我们就会发现,返回数据的响应头是'Access-Control-Allow-Origin': '127.0.0.1:8886',当浏览器在进行同源判定时,127.0.0.1:8888127.0.0.1:8886端口号不同,所以不是同源,会报错:
在这里插入图片描述

使用标签解决跨域

当网站开始执行脚本,会检测这个脚本的来源,如果这个脚本的来源与当前网站不同源的话,就会限制其执行,即受到同源策略的限制。有没有一种方式使其他来源的脚本转化成和当前页面同源的呢?
使用标签来加载非同源资源,当加载完成之后再注入到页面中,浏览器就会将其认为是同源的:

1 <img src=xxx>

2 <link href=xxx>

3 <script src=xxx>

我们修改index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <div>content</div>
</body>
<script src="http://127.0.0.1:8887"></script>
</html>

再次访问127.0.0.1:8888,查看8887端口返回的数据:
在这里插入图片描述
在这里插入图片描述
我们发现,即使8887返回数据的响应头中说明Access-Control-Allow-Origin: 127.0.0.1:8886,但是我们依旧可以拿到这个数据,并且控制台没有报错信息。

其实,这就是JSONP的实现机制,JSONP跨域是通过动态创建script标签,然后通过其src属性进行跨域请求的。

多个服务器请求同一个跨域资源

试想,我们现在增加一个server3

const http = require('http')
const fs = require('fs')

http.createServer(function (request, response){
  console.log('request url: ', request.url)

  const html = fs.readFileSync('index.html', 'utf-8')
  response.writeHead(200, {
    'Content-Type': 'text/html'
  })
  response.end(html)
}).listen(8886)

console.log('server running on 8886')

server3.jsserver.js唯一的不同就是监听的端口不一样,server3监听8886端口,现在我们面临一个问题就是:127.0.0.1:8888127.0.0.1:8886都需要向127.0.0.1:8887发送请求,如果我们还像之前那样,'Access-Control-Allow-Origin': 'http://127.0.0.1:8888',始终只能满足其中一个,如果我们使用正则或是通配符,有可能出现安全隐患。

这时候,我们可以设置一个共享资源地址的数组,然后如果来源地址在这个数组中,那么就将
Access-Control-Allow-Origin设置成对应的地址:
修改server2.js:

const http = require('http')

http.createServer(function (request,response){
  console.log('request url: ', request.url)
  const hosts = ['http://127.0.0.1:8888', 'http://127.0.0.1:8886']
  const shareUrl = ['http://127.0.0.1:8888/', 'http://127.0.0.1:8886/']
  let url = shareUrl.findIndex(item => item === request.headers.referer)
  response.writeHead(200, {
    'Access-Control-Allow-Origin': url > -1 ? hosts[url] : hosts[0]
  })
  response.end('123')
}).listen(8887)

console.log('server running on 8887')
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值