跳到主要内容位置

前端开发中如何解决跨域问题

在前端开发中,动不动就会出现跨域的问题,导致网络请求不成功,对于前后端分离的项目更是如此,这期视频我们就看一下跨域是什么,如何解决跨域问题。

什么是跨域

跨域全称是跨域资源共享(Cross-Origin Resources Sharing, CORS),它是浏览器的保护机制,只允许网页请求同一域名下的服务,同一域名的要求是,协议、域名和端口都要保持一致:

http://domain.com -> http://domain.com/api/user

如果有一项不同,那么就是跨域请求:

http://domain.com:3000 -> http://domain.com:5000/api/user http://domain.com ->
https://domain.com/api/user http://domain.com -> http://otherdomain.com/api/user

在前后端分离的项目中,解决跨域可以从 3 种情况下手:

  • 配置后端
  • 配置前端
  • 配置产品环境服务器

对于传统使用 jsonp 的形式,由于不适合 react 或 vue 之类的开发,并且也有安全隐患,这里就不作介绍了。

方法 1:配置后端

浏览器是否启用跨域保护机制是根据后端的响应来定的,所以配置后端是最直接的一种方法,浏览器根据的是响应的Access-Control-Allow-Origin 响应头来决定的:

img

如果这个字段的值是"*",那么会允许所有请求,如果是一个域名,那么浏览器就不会对这个域名下的请求进行跨域保护:

Access-Control-Allow-Origin: http://localhost:3000

根据后端程序的语言和库的不同,配置 Access-Control-Allow-Origin响应头的方法也不同,如果使用的是 node.js 和 express,那么可以添加 cors 中间件:

const cors = require("cors");

app.use(cors());

cors 默认会允许所有跨域请求,如果要限制指定域名,可以给它的 origin 配置项传递一个字符串或数组,用于指定一个或多个允许跨域的域名:

app.use(cors({ origin: ["http://domain1.com", "http://domain2.com"] }));

方法 2:配置前端

第 2 种方法,是在前端开发环境中,配置代理,中转请求,因为跨域是浏览器的保护机制,如果脱离的浏览器发送请求,是不会受到跨域保护机制的影响的,所以我们可以使用一个中转服务器来发送和接收请求,前端只需要请求这个中转服务器,并保持和中转服务器的 URL 保持一致即可。 ​

一般的前端脚手架工具都支持配置代理,例如 vite、create react app 等,这里以 vite 为例, vite 自带的开发服务器支持设置代理,在 vite.config.js 文件里,我们可以配置 server 配置项下的 proxy 配置,把对 /api 路径的请求代理转发到真实的后端服务路径,再根据需要,对转发的 URL 进行改写。

server: { proxy: { "/api": { target: "http://localhost:5000", changeOrigin:
true, rewrite: (path) => path.replace(/^\/api/, ""), }, }, },

这里的配置项把前端请求的 /api 路径转发到 http://localhost:5000/,并把 /api 这一段删除,因为这里后端提供的 API 中不带 /api 这一段:

/api -> http://localhost:5000 /api/user -> http://localhost:5000/user

这样在开发的时候,就避免了跨域问题。前端应用中可以直接请求 proxy 中配置的 /api 来请求后端服务,不用再写前边的协议、域名和端口了,因为默认是和前端相同的:

fetch("/api");

这个时候,如果去掉后端的跨域支持,前端仍然能请求后端的数据:

// const cors = require("cors");

// app.use(cors());

方法 3:产品环境

对于产品环境,或者开发服务器不支持代理的情况下,我们可以自己手动创建一个中转服务器来代理请求。 假设我们打包好的前端项目放到了 dist 目录下,入口文件为 index.html:

dist |-- index.html

我们可以使用 express 来创建一个服务器,负责发送前端页面,并代理请求。例如我们这里把让请求都返回 dist 下的 index.html 文件:

app.use(express.static("dist"));

// serve index.html for all routes
app.get("*", (req, res) => {
res.sendFile(__dirname + "/dist/index.html");
});

但是对于 /api 这个路径,我们还是需要配置代理,这里需要安装 http-proxy-middleware 依赖库,它和 vite 底层使用的代理服务是一样的,配置也几乎一样,不同的是 vite 中 rewrite 配置项这里叫作 pathRewrite:

const { createProxyMiddleware } = require("http-proxy-middleware");

app.use(
"/api",
createProxyMiddleware({
target: "http://localhost:5000",
changeOrigin: true,
// 这里是 pathRewrite,跟 vite 不太一样
pathRewrite: (path) => path.replace(/^\/api/, ""),
})
);

这样,我们再启动这个服务器来负责展现前端产品环境的页面,可以看到,仍然可以成功的请求的后端的数据。

node server_production.js

除了使用 express,也可以使用 nginx 等专业的服务器程序,你可以参考相关文档来配置代理。

小结

好了,这个就是如何解决前端跨域的方法,你学会了吗?如果有帮助请三连,想学更多有用的前端开发知识,请关注峰华前端工程师,感谢观看!

提示

一系列的课程让你成为高级前端工程师。课程覆盖工作中所有常用的知识点和背后的使用逻辑,示例全部都为工作项目简化而来,学完即可直接上手开发!

即使你已经是高级前端工程师,在课程里也可能会发现新的知识点和技巧,让你的工作更加轻松!

《React 完全指南》课程,连载中现只需 48 元(领取优惠券)点击查看详情。

《Vue 3.x 全家桶完全指南与实战》课程,包括 Vue 3.x、TypeScript、Vue Router 4.x、Vuex 4.x 所有初级到高级的语法特性详解,让你完全胜任 Vue 前端开发的工作。点击查看详情。

《React即时通信UI实战》课程,利用 Storybook、Styled-components、React-Spring 打造属于自己的组件库。

《JavaScript 基础语法详解》本人所著图书,包含 JavaScript 全面的语法知识和新特性, 可在京东、当当、淘宝等各大电商购买