本文为翻译作品,原文链接:How to use CORS in Next.js 14
在深入研究 Next.js 中的 CORS 之前,让我们一起回顾一下总体思路,以建立牢固的基础认识。
跨源资源共享(或 CORS)是一种安全机制,用于保护网站免受跨源请求的影响。
简单来说,"来源"指的是除你自己的域以外的任何域。
此外,"来源"被正式定义如下:
<协议>://<域名>:<端口号>
端口号可以是可选的,例如 <协议>://<域名> 也足够了。
请看下面的 CORS 操作,来源 x.com 尝试从来源 y.com 接收数据:
🗣️ 词语解释:
- x.com 发送预请求(也就是 HTTP OPTIONS 请求)以请求来自 y.com 的数据。
- y.com 随后检查请求的 Headers
- 如果启用了 CORS Headers 且 y.com 在白名单中,则向 x.com 发送数据。
- 如果禁用了 CORS Headers,或者 y.com 不在白名单中,则不向 x.com 发送数据。
那么你可能会问:"什么是 CORS Headers?"
有四个主要 CORS Headers 需要了解:
- Access-Control-Allow-Origin --- 指定可以访问该资源的来源
- Access-Control-Allow-Methods --- 添加到预检响应中,以指示允许的 HTTP 方法,如 GET、POST、PUT 等
- Access-Control-Allow-Headers --- 在响应预检请求时返回,以指定当前请求中允许的 HTTP 头
- Access-Control-Allow-Credentials --- 指示浏览器是否应在跨来源请求中包含诸如 cookies 或 HTTP 认证的凭证
现在我们已经熟悉了 CORS,及其在网页开发中的应用,让我们将这些理解应用到 Next.js 的项目中。
在 Next.js 中启用 CORS 的 3 种方式
请确保通过在终端窗口运行以下命令创建一个新的 Next.js 14 应用程序:
bash
npx create-next-app@latest
1. Next.js 配置 Headers
在你的应用程序根目录下的 next.config.js 文件中,你可以配置异步的 headers() 键,带有所需的 CORS Headers:
javascript
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
async headers() {
return [
{
// 在这里,你可以使用正则表达式添加你的来源 URL。
source: "<your-source-url(s)>",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
// 在这里添加你的白名单来源
{ key: "Access-Control-Allow-Origin", value: "<your-origin>" },
{ key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" },
]
}
]
}
}
module.exports = nextConfig
注意:
- 你可以使用路径正则表达式配置多个来源。例如,
/api/:path*
将匹配所有 api 路径。 - 你的来源将能够访问你的来源 URL API 数据;确保来源是可信任的。
2. 中间件
如果你需要在请求发送到你的来源之前应用 CORS Headers,则需要使用中间件。
在与你的 app/
目录同级的位置,创建一个名为 middleware.ts
的文件,并使用以下模板代码:
javascript
// src/middleware.ts 或 src/middleware.js
// https://blog.logrocket.com/using-cors-next-js-handle-cross-origin-requests/
import { NextResponse } from "next/server";
export function middleware() {
// 检索当前响应
const res = NextResponse.next()
// 向响应中添加 CORS Headers
res.headers.append('Access-Control-Allow-Credentials', "true")
res.headers.append('Access-Control-Allow-Origin', '<your-origin>')
res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT')
res.headers.append(
'Access-Control-Allow-Headers',
'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
)
return res
}
// 中间件只会应用于以下路由。
export const config = {
matcher: '<your-source-url(s)>',
}
你现在可以通过配置 matcher
来适配这段代码,它指定了你的来源可以访问的 source-urls。
3. Vercel 配置文件
假设你在 Vercel 上托管你的 Next.js 应用程序,你还可以在 Next.js 项目的根目录下添加一个 vercel.json
文件,并按照以下方式自定义它:
json
// 类似于 next.config.js 方法,但使用不同的路径正则表达式语法(参见 vercel.json 文档)。
// https://vercel.com/docs/projects/project-configuration#headers
{
"headers": [
{
"source": "<your-source-url(s)>",
"headers": [
{ "key": "Access-Control-Allow-Credentials", "value": "true" },
{ "key": "Access-Control-Allow-Origin", "value": "<your-origin>" },
{ "key": "Access-Control-Allow-Methods", "value": "GET,DELETE,PATCH,POST,PUT" },
{ "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }
]
}
]
}
针对多个端点调整 CORS 策略
目前,你只能为特定模式的来源(例如 api/:path*
)追加 Headers。
但假设你需要为另一个特定来源或多个来源应用特定的 CORS Headers。
使用中间件允许多个来源:
javascript
import { NextResponse } from "next/server";
// 所有允许的来源列表
const allowedOrigins = [
'http://localhost:3000',
'https://example-1.com',
'https://example-2.com',
// ...
'https://example-99.com',
];
export function middleware(req) {
// 检索当前响应
const res = NextResponse.next()
// 从传入请求中检索 HTTP "Origin" headers
req.headers.get("origin")
// 如果来源是允许的一个,
// 将其添加到 'Access-Control-Allow-Origin' headers
if (allowedOrigins.includes(origin)) {
res.headers.append('Access-Control-Allow-Origin', origin);
}
// 将剩余的 CORS Headers 添加到响应中
res.headers.append('Access-Control-Allow-Credentials', "true")
res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT')
res.headers.append(
'Access-Control-Allow-Headers',
'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
)
return res
}
// 中间件只会应用于以下路由。
export const config = {
matcher: '<your-source(s)',
}
使用 vercel.json
或 next.config.js
为额外的特定来源:
javascript
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
async headers() {
return [
{
// 匹配所有 API 路径
source: "/api/:path*",
headers: [
// 为了简洁省略...
]
},
// 额外的特定来源:/api/special-data
{
source: "/api/special-data",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "false" },
{ key: "Access-Control-Allow-Origin", value: "https://example.com" },
{ key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT" },
{ key: "Access-Control-Allow-Headers", value: "Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date" },
]
}
]
}
}
module.exports = nextConfig
总结
CORS 是一种重要的安全机制,它保护你的网站免受跨来源请求的侵害。使用本文介绍的三种方法,就可以正确为你的 Next.js 应用提升安全策略了。