美文网首页
前端基础:如何解决跨域问题

前端基础:如何解决跨域问题

作者: limengzhe | 来源:发表于2021-11-26 16:14 被阅读0次

本文首发于 前端基础:如何解决跨域问题

同源策略

同源策略是跨域问题的根本所在。

同源的“源”代表 origin,同源就表示两个 URL 的 origin 是相同的,originprotocolhostport 组成。

{
  "protocol": "http:",
  "host": "web.example.com",
  "port": "",
  "origin": "http://web.example.com"
}

同源策略是一个非常重要的安全策略,它用于限制两个源之间在浏览器上进行资源交互。如果缺少了同源策略,网站或服务器很容易受到 XSS、CSFR 等攻击。

以下方案假设:

前端域名:http://web.domain.com

后端域名:http://server.domain.com

运行在 http://web.domain.com 的 JavaScript 代码发起了一个到 http://server.domain.com/api/list 的 AJAX 请求。

方案一(最直接):设置 CORS 跨域资源共享

设置 CORS 是最直接的方法。该方案无需前端操作,只需后端在返回响应时设置响应头即可:

指定允许访问的域名:

{
  "Access-Control-Allow-Origin": "http://web.domain.com"
}

或者使用通配符 * ,表示所有网站都可以访问资源

{
  "Access-Control-Allow-Origin": "*"
}

方案二(最兼容):使用 Nginx 反向代理

同源策略仅存在于浏览器之间,服务器之间的交互不需要遵循同源策略。

所以我们这里可以使用 Nginx 作为 Web 服务器,监听并接收来自外部(其他服务器)请求,将接收到的请求使用和本机相同的域名转发到后端,然后再将响应转发给前端。

使用 Nginx 反向代理的必要设置如下:

// nginx.conf
server {
  listen 80;
  server_name web.domain.com;
  location / {
    proxy_pass server.domain.com;
  }
}

修改后需要重启 Nginx 服务器:

sudo nginx -s reload

方案三(最方便):前端使用 Webpack 代理

同样也是利用服务器向服务器请求无需遵循同源策略的特点。只不过这里我们使用 Webpack 作为本地的代理服务器。

该方案无需后端操作,只需在 webpack.config.js 中配置即可:

// webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      // 接口前缀
      '/api': {
        target: 'http://server.domain.com', // 指定服务器地址
      },
    },
  },
}

方案四(最古老):使用 JSONP

JSONP(JSON with Padding)主要是利用 <script> 标签加载脚本不受同源策略的限制这一特性,来加载需要请求的资源。

该方法需要后端和前端同时设置,且仅支持 GET 请求。

后端代码示例(以 node.js 为例):

const querystring = require('querystring')
const http = require('http')
const server = http.createServer()

server.on('request', function (req, res) {
  const params = qs.parse(req.url.split('?')[1])
  const fn = params.callback

  res.writeHead(200, { 'Content-Type': 'text/javascript' }) // 设置返回的 MIME 类型为 text/javascript
  res.write(fn + '(' + JSON.stringify(params) + ')') // 回调函数

  res.end()
})

server.listen('8080')

前端代码示例:

let script = document.createElement('script')

// 在 URL 后指定一个回调函数
script.src = 'http://server.domain.com/api/list?callback=handleCallback'
document.head.appendChild(script)

// 回调执行函数
function handleCallback(res) {
  console.log(res)
}

方案五(最新):使用 WebSocket

HTML5 定义了 Websocket 协议,该协议主要用于服务器和浏览器之间的持久化连接,并且没有同源策略的限制。

该方案需要后端提供 Websocket 接口,前端进行接收。

前端代码示例:

let ws = new WebSocket('ws://server.domain.com/api/list')

ws.onopen = function () {
  console.log('连接成功')
}

ws.onmessage = function (res) {
  console.log(res.data)
}

ws.onclose = function () {
  console.log('连接关闭')
}

后端代码示例(以 node.js 为例):

const WebSocket = require('ws')

const server = new WebSocket.Server({ port: 8080 })

server.on('connection', function (socket) {
  socket.on('message', function (data) {
    socket.send(data)
  })
})

如果仅仅是为了实现跨域,不推荐使用 Websocket。

相关文章

网友评论

      本文标题:前端基础:如何解决跨域问题

      本文链接:https://www.haomeiwen.com/subject/mjhxxrtx.html