# Nextjs服务端重定向导致的错误日志问题
# 问题背景
当前服务端会产生很多不必要的错误日志,虽然不影响服务运行,但对查看服务端日志有很大的干扰性,需要排查日志产生原因,并消除它
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Socket'
| property '_writableState' -> object with constructor 'WritableState'
| property 'afterWriteTickInfo' -> object with constructor 'Object'
--- property 'stream' closes the circle
at JSON.stringify ()
at Object.renderToHTML (/app/node_modules/next/dist/server/render.js:583:54)
at runMicrotasks ()
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async doRender (/app/node_modules/next/dist/server/base-server.js:687:38)
at async cacheEntry.responseCache.get.isManualRevalidate.isManualRevalidate (/app/node_modules/next/dist/server/base-server.js:796:28)
at async /app/node_modules/next/dist/server/response-cache/index.js:80:36
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (internal/errors.js:322:7)
at ServerResponse.setHeader (_http_outgoing.js:561:11)
at ServerResponse._res.setHeader (/app/node_modules/next/dist/server/base-server.js:127:24)
at setHeadersFromObject (/app/node_modules/next/dist/compiled/compression/index.js:46:680)
at ServerResponse.setWriteHeadHeaders (/app/node_modules/next/dist/compiled/compression/index.js:46:914)
at ServerResponse.writeHead (/app/node_modules/next/dist/compiled/compression/index.js:46:121)
at Function.App.getInitialProps (/app/build/server/pages/_app.js:4375:13)
at Object. (/app/node_modules/next/dist/shared/lib/utils.js:75:33)
at Generator.next ()
at asyncGeneratorStep (/app/node_modules/@swc/helpers/lib/_async_to_generator.js:23:28) {
code: 'ERR_HTTP_HEADERS_SENT'
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 问题分析
# 什么情况下产生
经过本地的测试,在不支持的浏览器访问带有重定向的页面时(在getServerSideProps里有重定向),就会产生错误日志;这是因为页面的重定向与判断浏览器不兼容的重定向冲突了,
代码一: _app.jsx文件代码,代码二: getServerSideProps实现服务端重定向的页面代码
// page/_app.jsx 文件内代码
App.getInitialProps = async ({ ctx }) => {
// ....
if (!browserInfo.compatible) {
res.writeHead(307, {
// 浏览器不兼容,重定向到xxx页面
Location: "/xxx.html",
});
return res.end();
}
//...省略余下代码
};
2
3
4
5
6
7
8
9
10
11
12
// page/index.jsx 任意页面下的getServerSideProps
export async function getServerSideProps({ req, query }) {
// 重定向到xxx页
return {
redirect: {
destination: encodeURI(`/xxx`),
permanent: false,
},
};
}
2
3
4
5
6
7
8
9
10
两次重定向会导致: Cannot set headers after they are sent to the client 报错的产生: getServerSideProps里重定向也会执行res.end方法,多次执行end就会触发这个报错;
‘ return res.end() ’ 会导致: TypeError: Converting circular structure to JSON 报错的产生; 因为nextjs会对getInitialProps方法返回的内容进行json序列化
# 如何解决
1、在getServerSideProps层添加是否已经做重定向的判断,如果已经重定向过了,就不在做重定向操作
优点: 不引入新功能,稳定
缺点: 需要修改多个文件,后续新增getServerSideProps的重定向时,都要做这个判断;
2、使用middleware (opens new window)功能,中间件拦截请求提前做一些处理
优点: 统一处理,修改快速
缺点: 每个请求都会走到这里,可能会存在影响服务性能问题
实现代码
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { getBrowser } from "./utils/getBrowser";
export function middleware(request: NextRequest) {
// 如果是请求文件地址,直接返回
if (
/^.+\.(?:(?:[a-zA-Z0-9]+)|(?:[a-zA-Z0-9]+\/[a-zA-Z0-9]+))$/.test(
request.nextUrl.pathname
)
) {
return NextResponse.next();
}
const ua = request.headers.get("user-agent");
const browser = getBrowser(ua);
if (!browser.compatible) {
return NextResponse.redirect(new URL("/browser.html", request.url));
}
return NextResponse.next();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
3、自定义后端服务 Advanced Features: Custom Server | Next.js (nextjs.org) (opens new window)
优点: 自定义程度更高
缺点: 工作量大
以前也排查过,为啥没有解决
以前nextjs版本比较低,当时也想用middleware来解决,但当时这个功能还不完善,用的过程中存在问题,所以就暂时搁置了。
现在nextjs升级过了,middleware功能处于稳定状态,可以正常使用了
← CI & CD