8

一日一技:next.js如何正确处理跨域问题?

 7 months ago
source link: https://www.kingname.info/2024/01/18/nextjs-cors/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一日一技:next.js如何正确处理跨域问题?

2024-01-18

28

1.1k

4 分钟

我以前一直使用Vue来写前端。去年下半年接手了一个基于React + Next.js的项目,于是顺带学习了一下Next.js。由于Next.js的特点,这个项目的前后端是放在一起的。一开始没什么问题,看了半天文档就上手了。

上周我们需要在另一个网页项目中,调用这个项目的后端接口,于是就需要处理跨域请求的问题。但我发现按照网上的方法,跨域问题依然存在。这个问题浪费了我不少时间,好在最后终于找到了原因。记录在这里,免得大家跟我一样踩坑。

为了复现这个问题,我们先来创建一个Next.js项目。执行代码创建代码脚手架:

npx create-next-app test_cors

使用TypeScript,其他选项选择默认,如下图所示:

20240118205107.png

命令执行完成以后,会生成一个test_cors文件夹,在文件夹中创建文件pages/api/test.ts。内容如下:

import { NextResponse } from 'next/server'


export const config = {
runtime: "edge"
}

export interface UserInfo {
name: string
age: number
address: string
}


const handler = async (req: Request): Promise<Response> => {

const user = (await req.json()) as UserInfo
return NextResponse.json({success: true,
msg: `你的名字是${user.name}, 今年${user.age}岁`})
}

export default handler;

如下图所示:

20240118210134.png

然后运行命令npm run dev。这个后端接口就启动起来了。我们可以使用Postman来进行测试:

20240118210223.png

接下来,我们来写一段HTML代码,触发跨域问题:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>API 请求示例</title>
<script>
// 当按钮被点击时执行此函数
function sendRequest() {
// 创建一个新的 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();

// 配置请求类型、URL 以及异步处理
xhr.open('POST', 'http://127.0.0.1:3000/api/test', true);

// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/json');
// ... 其他请求头设置

// 设置响应类型
xhr.responseType = 'json';

// 定义请求完成的回调函数
xhr.onload = function () {
if (xhr.status === 200) {
// 请求成功,处理响应数据
document.getElementById('response').innerText = JSON.stringify(xhr.response);
} else {
// 请求失败,处理错误
document.getElementById('response').innerText = '请求失败: ' + xhr.status;
}
};

// 发送请求
xhr.send(JSON.stringify({name: "青南", age: 20, "address": "上海"}));
}
</script>
</head>
<body>
<button onclick="sendRequest()">发送请求</button>
<div id="response"></div>
</body>
</html>

直接双击打开这个html文件,点击页面上的按扭,就会触发跨域报错,如下图所示:

20240118210503.png

然后,你在网上用关键词搜索next.js 跨域或者next.js cors,一般看到的文章都会让你直接在next.config.js文件中添加响应头,如下图所示:

20240118210706.png

你按照这些文章中写到方法加了配置,重启服务,然后用Postman来测试,你会发现返回的响应头里面确实已经有这几项了,如下图所示:

20240118210852.png

但当你使用HTML页面来测试时,跨域的报错还在。

你连续打开Google上面10篇讲Next.js跨域的文章,无论是中文博客还是英文博客,甚至你直接使用ChatGPT来问,他们给你的回复肯定都是上面的这个方法。但是无论你怎么测试,跨域问题还在。

实际上,跨域就是这样配置的。你的配置没有任何问题。问题出现在你的后端代码上,如下图所示:

20240118211330.png

首先你需要是一个POST请求,你才能执行await req.json()。而浏览器在判断能不能跨域时,会首先发送一个OPTIONS请求,如下图所示:

20240118211446.png

这个请求也会走到你的这段后端代码里面。但由于OPTIONS请求没有Body,于是代码运行到await req.json()时,就会报错。于是浏览器认为OPTIONS请求没有返回status 200,因此强行认为你的接口不支持跨域。

那么解决方法也非常简单,提前判断一下请求方法是不是OPTIONS就可以了:

if(req.method === 'OPTIONS') {
return NextResponse.next()
}

如下图所示:

20240118211857.png

运行效果如下图所示,跨域成功:

20240118211927.png

这个问题对于资深前端来说,可能不值一提。但对于后端兼职前端的人,或者第一次接触Next.js的人来说,可能是一个深坑,会浪费很多的时间。


未闻Code Telegram Channel开通了!每天都有各种开发小技巧更新,速来!!

20240118220059.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK