• 跨域解决方案


    什么是同源策略?

    1. 一个域下的js脚本未经允许的情况下,不能访问另一个域名下的内容。
    2. 通常判断跨域的依据是协议,域名,端口号是否相同,不同则跨域。
    3. 同源策略是对js脚本的一种限制,并不是对浏览器的限制,像img,script脚本请求不会有限制。
    4. 同源策略是一种安全协议
    5. 比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。
      如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源(例如switch host切域名)

    方案1: jsonp 跨域

    访问脚本链接后,这个脚本文件内容是,后台返回函数调用,且它的参数是后台给的数据,但是这个函数确是前端定义的,当前端执行了饭回的js文件内容,就是执行该函数,这样前端就拿到了后台传的数据。

    function jsonp(url, params, callback) {
      const callbackName = "jsonp_" + Date.now();
      const queryString = Object.keys(params)
        .map(
          (key) => encodeURIComponent(key) + "=" + encodeURIComponent(params[key])
        )
        .join("&");
      const script = document.createElement("script");
      script.src = url + "?" + queryString + "&callback=" + callbackName;
      window[callbackName] = function (data) {
        callback(data);
        document.head.removeChild(script);
        delete window[callbackName];
      };
      document.head.appendChild(script);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    jsonp("http://www.example.com/api", { user: "admin" }, function (data) {
      console.log(data);
    });
    
    • 1
    • 2
    • 3

    方案2: document.domain +iframe跨域

    两个页面都通过 js 强制设置 document.domain 为基础主域,就实现了同域。

    1.)父窗口:(http://www.domain.com/a.html)

    <iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
    <script>
        document.domain = 'domain.com';
        var user = 'admin'; 设置数据
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.)子窗口:(http://child.domain.com/b.html)

    document.domain = 'domain.com';
    // 获取父窗口中的变量
    alert(window.parent.user);  获取数据
    
    • 1
    • 2
    • 3

    方案3:nginx代理跨域

    通过 Nginx 配置反向代理,将跨域请求转发到同源接口,从而避免浏览器的同源策略限制。

    下面是一个示例配置,展示了如何通过 Nginx 实现跨域代理:

    server {
      listen 80;
      server_name your-domain.com;
    
      location /api {
        # 设置代理目标地址
        proxy_pass http://api.example.com;
        
        # 设置允许的跨域请求头
        add_header Access-Control-Allow-Origin $http_origin;
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
        add_header Access-Control-Allow-Credentials true;
        add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
        
        # 处理预检请求(OPTIONS 请求)
        if ($request_method = OPTIONS) {
          return 200;
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在上面的示例中,假设你的域名是 your-domain.com,需要代理访问 api.example.com。你可以将这个配置添加到 Nginx 的配置文件中。

    这个配置会将 /api 路径下的请求代理到 http://api.example.com。同时,通过添加 Access-Control-Allow-* 头部,允许跨域请求的来源、方法、头部等。

    这样,当你在前端发送请求到 /api 路径时,Nginx 会将请求代理到 http://api.example.com,并在响应中添加跨域相关的头部,从而解决跨域问题。注意要根据实际情况进行配置,包括监听的端口、域名和代理的目标地址等。

    方案4:nodejs中间件代理跨域

    使用 Node.js 构建一个中间件,在服务器端代理请求,将跨域请求转发到同源接口,然后将响应返回给前端。

    可以使用 http-proxy-middleware 模块来创建一个简单的代理服务器。下面是一个示例代码:

    const express = require('express');
    const { createProxyMiddleware } = require('http-proxy-middleware');
    
    const app = express();
    
    // 创建代理中间件
    const apiProxy = createProxyMiddleware('/api', {
      target: 'http://api.example.com', // 设置代理目标地址
      changeOrigin: true, // 修改请求头中的 Origin 为目标地址
      pathRewrite: {
        '^/api': '', // 重写请求路径,去掉 '/api' 前缀
      },
      // 可选的其他配置项...
    });
    
    // 将代理中间件应用到 '/api' 路径
    app.use('/api', apiProxy);
    
    // 启动服务器
    app.listen(3000, () => {
      console.log('Proxy server is running on port 3000');
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在上面的示例中,首先使用 express 框架创建一个服务器实例。然后,使用 http-proxy-middleware 模块创建一个代理中间件。通过配置代理中间件的 target 选项,将请求代理到目标地址 http://api.example.com

    你可以通过其他可选的配置项来进行更多的定制,例如修改请求头、重写请求路径等。在这个示例中,我们将代理中间件应用到路径 /api 下,即当请求路径以 /api 开头时,会被代理到目标地址。

    最后,启动服务器并监听指定的端口(这里是 3000)。

    请确保你已经安装了 express 和 http-proxy-middleware 模块,并将上述代码保存为一个文件(例如 proxy-server.js)。然后通过运行 node proxy-server.js 来启动代理服务器。

    现在,当你在前端发送请求到 /api 路径时,Node.js 代理服务器会将请求转发到 http://api.example.com,从而实现跨域访问。记得根据实际情况修改目标地址和端口号。

    方案5:后端在头部信息里面设置安全域名

    后端可以在响应的头部信息中设置 Access-Control-Allow-Origin 字段,指定允许跨域访问的域名。例如,在 Node.js 中可以使用 cors 模块来实现:

    const express = require('express');
    const cors = require('cors');
    const app = express();
    // 允许所有域名跨域访问
    app.use(cors());
    // 其他路由和逻辑处理...
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    方案6: 通过webpack devserver代理

    使用 webpack-dev-server 的代理功能可以实现在开发过程中的跨域请求。你可以配置 devServer 对象中的 proxy 选项来设置代理。下面是一个示例配置:

    module.exports = {
      // 其他配置项...
      devServer: {
        proxy: {
          '/api': {
            target: 'http://api.example.com', // 设置代理目标地址
            pathRewrite: { '^/api': '' }, // 重写请求路径,去掉 '/api' 前缀
            changeOrigin: true, // 修改请求头中的 Origin 为目标地址
          },
        },
      },
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在上面的示例中,我们配置了一个代理,将以 /api 开头的请求转发到 http://api.example.com。通过 pathRewrite 选项,我们去掉了请求路径中的 /api 前缀,以符合目标地址的接口路径。

    将上述配置添加到你的 webpack.config.js 文件中,然后启动 webpack-dev-server。现在,当你在前端发送以 /api 开头的请求时,webpack-dev-server 会将请求转发到目标地址,并返回响应结果。

    注意,这里的配置是针对开发环境下的代理,当你构建生产环境的代码时,代理配置不会生效。

    请确保你已经安装了 webpack-dev-server,并在你的 package.json 文件的 scripts 中添加启动命令,例如:

    {
      "scripts": {
        "start": "webpack-dev-server --open"
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行 npm start 或 yarn start 来启动 webpack-dev-server

    这样,通过配置 webpack-dev-server 的代理,你就可以在开发过程中实现跨域请求。记得根据实际情况修改目标地址和请求路径。

    方案7: CORS(跨域资源共享)

    在服务端设置响应头部,允许特定的域名或所有域名访问该资源。可以通过在响应头部中设置 Access-Control-Allow-Origin 字段来指定允许访问的域名。

    示例代码(Node.js + Express):

    const express = require('express');
    const app = express();
    
    // 允许所有域名访问
    app.use((req, res, next) => {
      res.setHeader('Access-Control-Allow-Origin', '*');
      next();
    });
    
    // 路由和处理逻辑
    // ...
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    方案8: WebSocket

    使用 WebSocket 协议进行通信,WebSocket 不受同源策略限制,因此可以在不同域之间进行双向通信。

    示例代码(JavaScript):

    const socket = new WebSocket('ws://example.com/socket');
    
    socket.onopen = () => {
      console.log('WebSocket connection established.');
      // 发送数据
      socket.send('Hello, server!');
    };
    
    socket.onmessage = (event) => {
      console.log('Received message from server:', event.data);
    };
    
    socket.onclose = () => {
      console.log('WebSocket connection closed.');
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    方案9: 代理服务器

    在同一域名下,前端通过发送请求给同域下的代理服务器,然后由代理服务器转发请求到目标服务器,并将响应返回给前端,实现跨域请求。

    示例代码(Node.js + Express):

    const express = require('express');
    const axios = require('axios');
    const app = express();
    
    app.get('/api/data', (req, res) => {
      // 向目标服务器发送请求
      axios.get('http://api.example.com/data')
        .then((response) => {
          // 将目标服务器的响应返回给前端
          res.json(response.data);
        })
        .catch((error) => {
          res.status(500).json({ error: 'An error occurred' });
        });
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    每日练习-8
    镜像构建上下文(docker Context)
    华为路由器交换机DHCP配置实例(二层、三层交换机)
    语音增强——基本谱减法及其python实现
    中国手机新进程:折叠屏出海的荣耀,5G中回归的华为
    chatGPT免费AI交互产品的应用
    无人机+遥控器:遥控数传链路二合一远距离传输遥控器技术详解
    Java中的方法是什么?(Java系列2)
    如何在Vuex中处理异步操作?
    rocketMQ之TIMEOUT_CLEAN_QUEUE异常
  • 原文地址:https://blog.csdn.net/formylovetm/article/details/126585679