跳至主要內容

九种跨域解决方案

Mr.Chen开发日志项目总结大约 3 分钟约 1017 字

九种跨域解决方案

1.jsonp

客户端

function jsonp({ url, params, callback }) {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script')
    window[callback] = function (data) {
      resolve(data)
      document.body.removeChild(script)
    }
    params = { ...params, callback } // wd=b&callback=show
    let arrs = []
    for (let key in params) {
      arrs.push(`${key}=${params[key]}`)
    }
    script.src = `${url}?${arrs.join('&')}`
    document.body.appendChild(script)
  })
}
jsonp({
  url: 'http://localhost:3000/say',
  params: { wd: 'Iloveyou' },
  callback: 'show'
}).then(data => {
  console.log(data)
})

服务端

let express = require('express')
let app = express()

app.get('/say', function (req, res) {
  let { wd, callback } = req.query
  console.log(wd)
  console.log(callback)
  res.end(`${callback}('我不爱你')`)
})
app.listen(3000)

2.cors

客户端

let xhr = new XMLHttpRequest()
document.cookie = 'name=xiamen' // cookie不能跨域
xhr.withCredentials = true // 前端设置是否带cookie
xhr.open('PUT', 'http://localhost:4000/getData', true)
xhr.setRequestHeader('name', 'xiamen')
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      console.log(xhr.response)
      console.log(xhr.getResponseHeader('name'))
    }
  }
}
xhr.send()

服务端

let express = require('express')
let app = express()
let whitList = ['http://localhost:3000'] //设置白名单
app.use(function (req, res, next) {
  let origin = req.headers.origin
  if (whitList.includes(origin)) {
    // 设置哪个源可以访问我
    res.setHeader('Access-Control-Allow-Origin', origin)
    // 允许携带哪个头访问我
    res.setHeader('Access-Control-Allow-Headers', 'name')
    // 允许哪个方法访问我
    res.setHeader('Access-Control-Allow-Methods', 'PUT')
    // 允许携带cookie
    res.setHeader('Access-Control-Allow-Credentials', true)
    // 预检的存活时间
    res.setHeader('Access-Control-Max-Age', 6)
    // 允许返回的头
    res.setHeader('Access-Control-Expose-Headers', 'name')
    if (req.method === 'OPTIONS') {
      res.end() // OPTIONS请求不做任何处理
    }
  }
  next()
})
app.put('/getData', function (req, res) {
  console.log(req.headers)
  res.setHeader('name', 'jw')
  res.end('我不爱你')
})
app.get('/getData', function (req, res) {
  console.log(req.headers)
  res.end('我不爱你')
})
app.use(express.static(__dirname))
app.listen(4000)

3.postMessage

客户端

      <iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe>
      <script>
    function load() {
      let frame = document.getElementById('frame');
      frame.contentWindow.postMessage('我爱你','http://localhost:4000');
      window.onmessage = function (e) {
        console.log(e.data);
      }
    }
       window.onmessage = function (e) {
      console.log(e.data);
      e.source.postMessage('我不爱你',e.origin)
    }
      </script>

服务端

let express = require('express')
let app = express()
app.use(express.static(__dirname))
app.listen(4000)

4.name

客户端

a和b是同域的 http://localhost:3000 c是独立的 http://localhost:4000 a获取c的数据
a先引用c c把值放到window.name,把a引用的地址改到b
<iframe
  src="http://localhost:4000/c.html"
  frameborder="0"
  onload="load()"
  id="iframe"
></iframe>
<script>
  let first = true
  function load() {
    if (first) {
      let iframe = document.getElementById('iframe')
      iframe.src = 'http://localhost:3000/b.html'
      first = false
    } else {
      console.log(iframe.contentWindow.name)
    }
  }
</script>

服务端

let express = require('express')
let app = express()
app.use(express.static(__dirname))
app.listen(3000)

5.hash

<!-- 路径后面的hash值可以用来通信  -->
<!-- 目的a想访问c -->
<!-- a给c传一个hash值 c收到hash值后  c把hash值传递给b b将结果放到a的hash值中-->
<iframe src="http://localhost:4000/c.html#iloveyou"></iframe>
<script>
  window.onhashchange = function () {
    console.log(location.hash)
  }
  console.log(location.hash)
  let iframe = document.createElement('iframe')
  iframe.src = 'http://localhost:3000/b.html#idontloveyou'
  document.body.appendChild(iframe)
</script>

6.domain

<!-- 域名 一级域名二级域名 -->
<!-- www.baidu.com -->
<!-- viode.baidu.com -->
<!-- a是通过 http://a.zf1.cn:3000/a.html -->
helloa
<iframe
  src="http://b.zf1.cn:3000/b.html"
  frameborder="0"
  onload="load()"
  id="frame"
></iframe>
<script>
  document.domain = 'zf1.cn'
  var a = 100
  function load() {
    console.log(frame.contentWindow.a)
  }
</script>

7.websocket

客户端

// 高级api 不兼容 socket.io(一般使用它)
let socket = new WebSocket('ws://localhost:3000')
socket.onopen = function () {
  socket.send('我爱你')
}
socket.onmessage = function (e) {
  console.log(e.data)
}

服务端

let express = require('express')
let app = express()
let WebSocket = require('ws')
let wss = new WebSocket.Server({ port: 3000 })
wss.on('connection', function (ws) {
  ws.on('message', function (data) {
    console.log(data)
    ws.send('我不爱你')
  })
})

8.nginx

客户端

   var xhr = new XMLHttpRequest();
   // 前端开关:浏览器是否读写cookie
   xhr.withCredentials = true;
   // 访问nginx中的代理服务器
   xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
   xhr.send();

服务端

var http = require('http')
var server = http.createServer()
var qs = require('querystring')

server.on('request', function (req, res) {
  var params = qs.parse(req.url.substring(2))

  // 向前台写cookie
  res.writeHead(200, {
    'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取
  })

  res.write(JSON.stringify(params))
  res.end()
})

server.listen('8080')
console.log('Server is running at port 8080...')

9.node 中间件代理

客户端

    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script>
      $.ajax({
    url: 'http://localhost:3000',
    type: 'post',
    data: { name: 'xiamen', password: '123456' },
    contentType: 'application/json;charset=utf-8',
    success: function(result) {
      console.log('result', result)
    },
    error: function(msg) {
      console.log(msg)
    }
      })
    </script>

服务端

const http = require('http')
// 第一步:接受客户端请求
const server = http.createServer((request, response) => {
  // 代理服务器,直接和浏览器直接交互,需要设置CORS 的首部字段
  response.writeHead(200, {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': '*',
    'Access-Control-Allow-Headers': 'Content-Type'
  })
  // 第二步:将请求转发给服务器
  const proxyRequest = http
    .request(
      {
        host: '127.0.0.1',
        port: 4000,
        url: '/',
        method: request.method,
        headers: request.headers
      },
      serverResponse => {
        // 第三步:收到服务器的响应
        var body = ''
        serverResponse.on('data', chunk => {
          body += chunk
        })
        serverResponse.on('end', () => {
          console.log('The data is ' + body)
          // 第四步:将响应结果转发给浏览器
          response.end(body)
        })
      }
    )
    .end()
})
server.listen(3000, () => {
  console.log('The proxyServer is running at http://localhost:3000')
})
上次编辑于: