一分种搞定跨域问题

446 阅读6分钟

什么是跨域问题

跨域问题”是指浏览器为了安全考虑而实施的一种限制策略,称为“同源策略”(Same-origin policy)。同源策略规定一个网页中的脚本只能读取或操作来自同一源的资源。这里的“源”由协议,域名端口号三部分组成。如果两个页面的这三部分有任何一项不同,则这两个页面被视为来自不同的 源。

假如我们有一串Http 地址:www.example.com:8080/path/to/res…

  • 协议:HTTP
  • 域名:www.example.com
  • 端口:8080
  • 路径:/path/to/resource

我们要保证协议,域名,端口3个相同才能进行访问

我们自己做的项目,前后端可能不在一个端口,这个时候,就会出现跨域问题,那么怎么解决跨域问题呢?

解决跨域问题常见的几种方法

1.JSONP

我们在script标签里面写JS代码,向一个不符合同源策略的端口发送接口请求可能会出现跨域问题,但是如果我们这样

 <script src="https://github.com/vuejs/core">  //Vue3 源码地址

这样就可以引入Vue3里面的东西了

写在script标签里面写代码,会发生跨域问题,直接向这样

 <script src="https://github.com/vuejs/core">  //Vue3 源码地址

就不用考虑同源策略问题了

思考

我们是不是可以在接口请求里面动态创建script 标签,这样是不是就不用考虑跨域问题了?

JSON其实JSONP解决跨域问题的原理就是这样,JSONP 利用了 <script> 标签不受同源策略限制的特点,通过动态插入 <script> 标签来发起跨域请求,并通过回调函数接收和处理数据。这种方法仅适用于 GET 请求,因为 <script> 标签只支持 GET 方法。

前端示例代码

  1. 创建回调函数:

    • 在前端页面中定义一个全局函数,该函数将被用来处理服务器返回的数据。
  2. 构建请求URL:

    • 构建一个URL,其中包含回调函数的名字作为查询参数的一部分。
  3. 动态插入 <script> 标签:

    • 创建一个 <script> 标签,并将其 src 属性设置为上述URL。
    • 将 <script> 标签插入到DOM中,浏览器将自动发起请求。
  4. 服务器响应:

    • 服务器接收到请求后,返回一个包含回调函数名称和数据的JavaScript代码片段。
  5. 执行回调函数:

    • 浏览器执行从服务器返回的JavaScript代码,从而调用之前定义的回调函数,并将数据作为参数传递给该函数。

前端


  <!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>JSONP Example</title>
</head>

<body>
    <script>
        function handleResponse(data) {
            console.log('Data received:', data);
        }

        const Url = 'http://api.example.com/data?callback=handleResponse';

        const scriptTag = document.createElement('script');
        scriptTag.src = Url;
        document.head.appendChild(scriptTag);
    </script>
</body>

</html>

后端

const express = require('express');
const app = express();

app.get('/data', (req, res) => {
const callback = req.query.callback; // 获取回调函数名
const data = { message: 'Hello from the server!' };

// 构造 JSONP 响应
const jsonpResponse = `${callback}(${JSON.stringify(data)})`;
res.setHeader('Content-Type', 'application/javascript');
res.send(jsonpResponse);
});

app.listen(8080, () => {
console.log('Server is running on port 8080');
});

为什么要向后端传一个callback 函数体?

  1. 动态生成 JavaScript 代码:

    • 服务器需要知道客户端期望的回调函数名称,以便能够在返回的响应中生成正确的 JavaScript 代码片段。服务器将数据包装在这个回调函数的调用中返回。
  2. 执行回调函数:

    • 当浏览器加载 <script> 标签时,它会执行从服务器返回的 JavaScript 代码。这包括调用客户端定义的回调函数,并将数据作为参数传递给该函数。

!!!!JSONP 只能适用于Get 请求

2.Cors

第一步:安装cors npm install cors

第二步: 引入 Cors 中间件

    const express = require('express');
    const cors = require('cors');
    const app = express();
`

第三步: 引入 Cors中间件

现在您需要配置 cors 中间件。根据您的需求,可以选择以下几种配置方式之一:

允许所有源

如果您希望允许所有源进行跨域请求,可以简单地调用 cors() 函数,如下所示:

app.use(cors());

允许特定源

如果您只想允许特定的源进行跨域请求,可以使用 cors 的选项对象来指定这些源:


    app.use(cors({
        origin: 'http://your-allowed-origin.com'
    }));

这里,origin 选项指定了一个具体的域名作为允许的源。

设置其他CORS头部

您还可以设置其他CORS相关的HTTP头部,例如允许的HTTP方法、允许的头部等。例如:

    
       app.use(cors({
            origin: 'http://your-allowed-origin.com',
            methods: ['GET', 'POST', 'PUT', 'DELETE'], // 允许的HTTP方法
            allowedHeaders: ['Content-Type', 'Authorization'], // 允许的头部
            credentials: true, // 是否允许携带cookies
            maxAge: 86400 // 预检请求的有效期(单位:秒)
        }));

3.WebSocket

WebSocket 是一种网络通信协议,它提供了一个全双工的通信通道,可以在客户端和服务器之间进行双向数据传输。在使用 WebSocket 时,浏览器会先发起一个 HTTP 升级请求到服务器,请求将连接从 HTTP 协议升级为 WebSocket 协议。一旦连接建立成功,就可以绕过浏览器的同源策略(Same-Origin Policy)限制,因此在某种程度上可以解决跨域问题。

    
    // 创建一个新的 WebSocket 连接
var socket = new WebSocket('ws://example.com/ws');

// 连接成功后触发
socket.onopen = function (event) {
    console.log("Connection opened");
};
//连接关闭后触发
socket.onclose = function (event) {
    console.log("Connection closed");
};

//收到消息后触发
socket.onmessage = function (event) {
    console.log("Received: " + event.data);
};

WebSocket 的工作原理

  1. 握手

    • 客户端发起一个 HTTP 升级请求到服务器,请求将连接从 HTTP 协议升级为 WebSocket 协议。
    • 服务器响应这个请求,确认升级到 WebSocket 协议。
    • 一旦握手成功,连接就从 HTTP 升级到了 WebSocket,此时可以开始发送和接收数据。
  2. 数据传输

    • WebSocket 连接建立后,客户端和服务器都可以主动发送数据。
    • 数据是以帧的形式发送的,可以是文本或二进制数据。
  3. 关闭连接

    • 任何一方都可以关闭连接。
    • 关闭连接通常涉及发送一个特殊的关闭帧。

使用 WebSocket 解决跨域问题

由于 WebSocket 的设计方式,它天然支持跨域通信。这意味着,一旦客户端和服务器完成了握手过程,就可以绕过浏览器的同源策略限制,实现跨域的数据传输。

4.代理

创建或修改 vue.config.js 文件

首先,你需要在项目的根目录下创建一个名为 vue.config.js 的文件,如果已经有这个文件,可以直接编辑它。这个文件用于配置 Vue CLI 的构建行为。

步骤 2: 配置代理

vue.config.js 文件中,你需要定义一个 devServer 对象,其中包含代理规则。以下是一个简单的代理配置示例:


module.exports = {
    devServer: {
        proxy: {
            '/api': {
                target: 'http://example.com', // 你要代理的目标服务器地址
                changeOrigin: true,           // 如果目标服务器验证主机名,则需要此选项
                pathRewrite: {                // 重写路径
                    '^/api': ''                 // 移除路径中的 /api
                }
            }
        }
    }
}



详解配置项

  • target:这是你希望代理请求到的目标服务器地址。可以是完整的 URL(包括协议头)。
  • changeOrigin:默认情况下,代理服务器会保留原始请求的主机头。如果目标服务器验证主机名,那么你需要设置 changeOrigin: true,这样代理服务器会更改请求头中的主机头,使其看起来像是直接从代理服务器发出的请求。
  • pathRewrite:这是一个对象,用于重写代理请求的路径。例如,在上面的例子中,所有的 /api 路径都会被重写为空字符串,即移除 /api

以上是一些常见的解决跨域问题的方法