跨域

916 阅读2分钟

什么是跨域?

跨域, 是指浏览器不能执行其他网站的脚本。浏览器出于安全方面的考虑,只允许与同源下的接口交互,也就是浏览器的同源策略。同源策略会阻止跨域。

什么是同源?

同源必须要做到以下三点:同协议,同域名,同端口

被请求页面的协议、域名、端口中任意一个与当前页面不同即为跨域

当前页面URL被请求页面URL是否同源原因
www.123.comwww.123.com/do协议、域名、端口都相同
www.123.comwww.123.com协议不同(https/http)
www.123.com123.com域名不同(www.123.com/123.com)
www.123.com:8080www.123.com:9090端口不同(8080/9090)

跨域的解决办法

  1. JSONP

原理:

1.同源策略只限制 Ajax 请求,不限制 script 标签加载 js。可以通过 script 标签请求 资源,并提前写好接收函数。

2.服务器收到请求后,从 callback 参数得到 fn,把原始数据(假设是 {a:1})处理 后变成 handleData({a:1})

3.script 里的资源加载后会当成 js 执行,相当于执行 handleData({a:1}), 即可在预 定义的 handleData 函数里处理数据

代码:服务器端:

const http = require('http')
const url = require('url')

http.createServer((req, res)=>{
  let urlObj = url.parse(req.url, true)
  if(urlObj.pathname === '/getWeather'){
    let data = {city:'杭州',weather:'晴天'}
    res.end(`${urlObj.query.callback}(${JSON.stringify(data)})`)
  }else{
    req.writeHead(404,'404 not found')
    res.end('404 Not Found')
  }
}).listen(2020)

console.log('监听 http://127.0.0.1:2020')

前端页面js:

<script>
  function showData(data) {
    console.log(data) //
  }
</script>
<script src="http://127.0.0.1:2020/getWeather?callback=showData"></script>

在函数showData中即可获得数据。

  1. CORS

原理:发送Ajax请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin。后台收到请求后,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin;浏览器判断该响应头中是否包含 当前Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果没有浏览器直接驳回。

服务器代码:

const http = require('http')
const url = require('url')

http.createServer((req, res)=>{
  let urlObj = url.parse(req.url, true)
  if(urlObj.pathname === '/getWeather'){
    res.setHeader('Access-Control-Allow-Origin', 'https://www.baidu.com')
    res.end(JSON.stringify( { city: 'hangzhou', weather: 'sunny' } ))
  }else {
    res.writeHead(404, 'Not Found')
    res.end('not found')
    }

}).listen(9090)

console.log('可以在 https://www.baidu.com 中访问getWeather接口了!')

www.baidu.com 控制台获取数据:

fetch('http://127.0.0.1:9090/getWeather')
  .then(res => res.json())
  .then(data => console.log(data))

即可获得数据:{city: "hangzhou", weather: "sunny"}

  1. 服务器中转()

服务器代码:

const http = require('http')
const url = require('url')

http.createServer((req, res)=>{
  let urlObj = url.parse(req.url, true)
  if(urlObj.pathname === '/bridge'){
    http.get(urlObj.query.url,req =>{
      let text = ''
      req.on('data', data => text += data)
      req.on('end',()=>{
        res.setHeader('Access-Control-Allow-Origin','*')
        res.end(text)
      })
    })
  }
}).listen(8888)
console.log('监听 http://127.0.0.1:8888')
//当前代码在其他网页下运行
fetch('http://localhost:8888/bridge?url='+encodeURIComponent('http://baidu.com'))
.then(res=>res.text())
.then(data => console.log(data))