前端跨域终极指南:3 种优雅解决方案 + 可运行 Demo

发布于:2025-09-05 ⋅ 阅读:(18) ⋅ 点赞:(0)

在这里插入图片描述

摘要

在前端开发中,我们经常会遇到这样一个问题:明明接口写好了,地址也对,结果一请求就报错——跨域请求被拦截。这其实不是接口坏了,而是浏览器为了安全做的限制。本文会结合实际开发的环境,从后端配置、前端代理到一些“老办法”来讲清楚如何处理跨域问题,还会提供一个可运行的小 Demo,帮你快速上手。

引言

现在的前端项目,基本都是前后端分离的模式。前端项目一般跑在 3000 或者 5173 这种端口,而后端可能是 5000、8080,甚至部署在一个独立的服务器上。只要协议、域名或者端口不一样,浏览器就会认为是跨域。这个时候,如果后端不配合,就会报错。

所以我们得找到合适的方式去处理它。常见的思路有三种:

  • 让后端放行(配置 CORS 响应头)
  • 在开发环境用代理转发(前端配置 dev server)
  • JSONP(老方法,现在基本不用了,但了解一下也行)

接下来我们逐个展开。

后端配置 CORS 允许

为什么要这么做

从根源上解决跨域问题的方式就是让后端告诉浏览器:“这个请求是安全的,可以放行”。这需要在服务端返回响应头的时候加上一些特殊的字段,比如 Access-Control-Allow-Origin

代码示例

假设你后端用的是 Express,只需要写一个中间件:

// server.js
import express from "express";

const app = express();

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*"); // 允许所有域名
  res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
  res.header("Access-Control-Allow-Headers", "Content-Type,Authorization");
  next();
});

app.get("/hello", (req, res) => {
  res.json({ msg: "Hello from backend!" });
});

app.listen(5000, () => {
  console.log("Server running on http://localhost:5000");
});

这个配置之后,你的前端直接请求 http://localhost:5000/hello 就能拿到结果。

适用场景

这种方式适合:

  • 后端和前端都是你自己能控制的项目
  • 生产环境的接口调用

前端代理转发

为什么要这么做

有时候后端不是你写的,或者你没法修改配置。那就只能在本地开发的时候想点办法。最常见的办法就是配置前端的 dev server 代理。

代码示例

比如你用 Vite

// vite.config.js
export default {
  server: {
    proxy: {
      "/api": {
        target: "http://localhost:5000", // 后端服务地址
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },
};

然后前端只需要这样写:

// frontend/src/main.js
import axios from "axios";

axios.get("/api/hello").then((res) => {
  console.log(res.data);
});

实际请求的时候,Vite 会帮你把 /api/hello 转发到 http://localhost:5000/hello,这样就不会触发浏览器的跨域限制。

适用场景

这种方式常见于:

  • 本地开发调试
  • 前端没法改后端配置的时候

JSONP(了解即可)

为什么要这么做

在 CORS 没普及之前,大家会用 JSONP 绕过跨域。它的原理很简单:<script> 标签不受跨域限制,于是把数据包装成一个函数调用,通过 script 动态加载执行。

代码示例

<script>
function handleData(data) {
  console.log("拿到数据:", data);
}
</script>
<script src="http://localhost:5000/jsonp?callback=handleData"></script>

服务端返回:

handleData({ msg: "Hello JSONP" });

虽然能用,但只能用于 GET 请求,现在已经不推荐了。

实际应用场景举例

场景1:前端调用第三方 API

比如你要在前端直接调用天气预报接口,但对方没有开放跨域支持。这时候,你可以在本地搭一个代理服务器,把请求转发到第三方 API。

// vite.config.js
proxy: {
  "/weather": {
    target: "https://api.weather.com",
    changeOrigin: true,
    rewrite: (path) => path.replace(/^\/weather/, ""),
  },
}

请求的时候:

axios.get("/weather/v3/wx/forecast").then((res) => {
  console.log(res.data);
});

场景2:前后端分离项目的本地调试

后端跑在 http://localhost:5000,前端跑在 http://localhost:5173。如果后端能改,就直接加上 CORS 配置。如果后端不能改,那就在 Vite 里加代理。


场景3:生产环境 API 网关

有些公司会在生产环境用 Nginx 做反向代理,比如:

location /api {
    proxy_pass http://127.0.0.1:5000;
}

这样前端永远只请求 /api,实际请求被网关转发到后端,也能避免跨域。

QA 环节

Q1: 如果后端没有设置 CORS,我是不是一定要用代理?
A1: 是的,因为跨域拦截发生在浏览器端,你前端没法绕过,只能靠代理或者 JSONP。

Q2: 为什么我配置了 Access-Control-Allow-Origin 还是报错?
A2: 很可能是 OPTIONS 预检请求没处理好,需要返回 200,并且带上允许的请求头。

Q3: 开发环境用代理,生产环境要怎么处理?
A3: 最好还是让后端加 CORS。如果不行,就让运维在网关层(比如 Nginx)做反向代理。

总结

跨域问题看起来麻烦,其实只要理解原理,就会发现思路很清晰:

  • 如果你能改后端,那就直接加上 CORS 配置,从根源解决
  • 如果你只能改前端,那就在开发环境用代理转发
  • JSONP 只是历史遗留,了解一下即可

换句话说,跨域问题并不是 bug,而是浏览器的安全机制。学会这几种处理方式,就能在不同的场景下优雅地搞定它。


网站公告

今日签到

点亮在社区的每一天
去签到