跨域的解决方案

一、概念

1. 浏览器的同源策略

浏览器为确保资源的安全,而遵循的一种策略。

2. 源

源 = 协议 + 域名 + 端口

3. 同源和非同源

当两个源只有他们的协议、域名、端口都一致,才是同源,否则是非同源。

4. 同源请求和非同源请求

如果是同源发出的请求就是同源请求,如果是非同源发出的请求就是非同源请求。

5. 跨域

所处源 与 目标源 不一致,就会导致跨域。

二、浏览器会对跨域做哪些限制

源 A 和 源 B是非同源的,则浏览器会有以下限制。

1. DOM 访问限制

源 A的脚本不能读取和操作源 B的 DOM

源 A不能访问源 B的 Cookie

3. Ajax 响应数据限制

源 A可以给源 B发请求,但无法获取源 B的返回的数据

三、注意点

跨域限制仅存在浏览器端,服务端不存在跨域限制

即时跨域了,Ajax 请求也可以正常发出,但响应数据不会交给开发者。

<link>、<script>、<img>...这些标签发出的请求也可能跨域,只不过浏览器对标签不做严格限制,对开发几乎无影响。

四、CORS 解决跨域

CORS 即跨源资源共享(Cross-Origin Resource Sharing),CORS 是一种机制,它允许 Web 应用服务器进行跨域访问控制,使不同源的网站之间能够安全地共享资源。

在默认情况下,出于安全考虑,浏览器会限制从一个源(协议、域名、端口)加载的脚本获取或操作另一个源的资源。而 CORS 为 Web 应用提供了一种安全的方式来绕过这种同源策略的限制。

使用 CORS 解决跨域是最正统的方式,且要求服务器是"自己人"

1. 简单请求和复杂请求

简单请求

**请求方式:**GET、HEAD、POST

**Content-type:**text/plain、multipart/form-data、application/x-www-form-urlencoded

请求头字段符合《CORS 安全规范》,只要你改了请求头就变复杂请求了。

复杂请求

不是简单请求就是复杂请求,复杂请求会自动发送预检请求。

2. 解决简单请求

以 nodeJS 为例,服务器端设置响应头 Access-Control-Allow-Origin,值为发送请求的源表示,只要从这个源发送的请求,都通过。值为 "\*" 表示所有不同源发来的请求都通过。

javascript 复制代码
app.get("/xxx", (res, req) => {

  res.setHeader("Access-Control-Allow-Origin", "发送请求源" | "*");

  res.send();

});

3. 解决复杂请求

以 nodeJS 为例,服务器设置响应头,与请求头一一对应,使用 cors 插件。

javascript 复制代码
app.use(

  cors({

    origin: "xxx", // 允许源

    methods: ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"], // 允许方法

    allowedHeaders: ["xxx"], // 允许的自定义头

    exposedHeaders: ["xxx"], // 要暴露的响应头

  })

);



app.get("/xxx", (res, req) => {

  res.setHeader("xxx", "xxx");

  res.send();

});

五、JSONP 解决跨域

JSONP 利用<script>标签可以跨域加载脚本,且不受严格模式限制的特性。

1. 基本流程

**第一步:**创建 script 标签,将 src 设置为跨域请求的 url。同时准备一个回调函数,这个函数处理返回来的数据。

**第二步:**服务端接受到请求后,将数据封装在回调函数中返回

**第三步:**客户端回调函数被调用,数据以参数的形式传入回调函数

2. 例子

服务端代码

javascript 复制代码
let list = [1, 2, 3];

app.get("/table", (req, res) => {

  const { callback } = req.query;

  res.send(`${callback}(${JSON.stringify(list)})`);

});

客户端代码

javascript 复制代码
function test(data) {

  console.log(data);

}

function getTable() {

  const script = document.createElement("script");

  script.onload = () => {

    script.remove();

  };

  script.src = "http://xxx.xx.xx:8080/table?callback=test";

  document.body.appendChild(script);

}

六、配置代理解决跨域

1. 自己配置代理服务器

借助 http-proxy-middleware 配置代理

javascript 复制代码
const { createProxyMiddleware } = require("http-proxy-middleware");

app.use(

  "/api",

  createProxyMiddleware({

    target: "https://www.baidu.com",

    changeOrigin: true,

    pathRewrite: {

      "^/api": "",

    },

  })

);

2. 使用 Nginx 搭建代理服务器

2.1 设置响应头

javascript 复制代码
server {

    listen 80;

    server_name your_domain.com;



    location /api/ {

        add_header 'Access-Control-Allow-Origin' '*';

        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

        add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';



        if ($request_method = 'OPTIONS') {

            return 204;

        }



        proxy_pass http://your_backend_server;

    }

}

2.2 反向代理

通过 Nginx 将跨域请求代理到目标服务器,让浏览器认为是同源请求。

javascript 复制代码
server {

    listen 80;

    server_name frontend.com;



    location /api/ {

        proxy_pass http://backend.com;

    }

}

3. 脚手架服务器

比如 vue3 里的配置文件 vite.config.js 可以配置代理的地址

javascript 复制代码
import { defineConfig } from "vite";

// https://vitejs.dev/config/
export default defineConfig(() => {
  return {
    server: {
      host: "127.0.0.1",
      port: 8081,
      strictPort: false,
      open: true,
      proxy: {
        "/dev-api": {
          target: "http://localhost:1112",
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/dev-api/, ""),
        },
      },
    },
  };
});
相关推荐
雪芽蓝域zzs7 小时前
第 5 节:Marker 点击弹出 InfoWindow 信息窗口
vue.js
回眸&啤酒鸭7 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户69371750013848 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员8 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
小兔子8 小时前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端
IT_陈寒8 小时前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
guslegend9 小时前
脚手架原理与本地调试:从 bin 软链接到 npm link
前端·npm·node.js·脚手架·前端工程化
小宋10219 小时前
A2UI从零实战:Agent安全生成交互界面与事件回传
javascript·人工智能·安全·交互
大包子10 小时前
structuredClone vs lodash.cloneDeep:核心差异与选型指南
javascript·vue.js
海码事务所10 小时前
Google Play 新个人开发者账号上架指南:12 人连续 14 天封闭测试怎么做?
前端