Q: 我们平常用next.js的时候,500页面除了改改样式,就不能做更多的定制化了,如果想显示接口抛出的具体错误code,方便用户反馈bug怎么办呢?
解决办法,直接上代码
const Error = ({ statusCode }: ErrorProps) => {
// hack
const [errCode, setErrCode] = useState('')
useEffect(() => {
try {
const p = JSON.parse(
document.getElementById('__NEXT_DATA__')?.textContent as string
)
setTraceid(p.props.pageProps.errCode)
} catch (err) {}
}, [])
return (
<>
<h1>500</h1>
<div>{errCode}</div>
</>
)
}
Error.getInitialProps = async ({
res,
err,
pathname,
query,
AppTree,
}: NextPageContext) => {
const errorInitialProps = await NextError.getInitialProps({
res,
err,
pathname,
query,
AppTree,
})
let errCode = err.code
return {
...errorInitialProps,
errCode,
}
}
export default Error
Q: 代码一看就懂,但是为什么要这样呢?
getInitialProps 返回的 errCode 是会丢失的。直接用props去接收errCode你就会发现页面上的errCode闪烁一下就消失了。
假设如果用props去接收errCode会发生什么?
next.js渲染是分为两部分的,首先是服务端渲染出html显示到页面上, 然后客户端再次渲染出html替换掉服务端渲染的html(这个过程叫做hydrate)。
首先服务端渲染出的结果是没有问题的,但是客户端hydrate的过程中渲染出来的结果是没有errCode的导致了上述现象的发生
Q: 为什么客户端渲染的时
props.errCode丢失了
我的的errCode是从err.code取出来的
- 服务端调用
getInitialProps({err: err})时用的是代码里throw出的原始错误 - 客户端调用
getInitialProps({err: err})时用的错误是
{
message: "500 - Internal Server Error."
name: "Internal Server Error."
statusCode :500
}
所以客户端渲染时 errCode 返回的就是undefined,然后就从页面消失了。
Q: 为什么这个错误变掉了?
直接上next.js源码,nextjs在序列化error给客户端用时调用了以下函数
function serializeError(
dev: boolean | undefined,
err: Error
): Error & {
statusCode?: number
source?: typeof COMPILER_NAMES.server | typeof COMPILER_NAMES.edgeServer
} {
if (dev) {
return errorToJSON(err)
}
return {
name: 'Internal Server Error.',
message: '500 - Internal Server Error.',
statusCode: 500,
}
}
这里原始错误就消失了
到此已经全部明了,我们只要拿到next.js服务端返回的原始数据就可以解决最开始的问题了。
next.js服务端返回的原始数据怎么拿呢
const p = JSON.parse(
document.getElementById('__NEXT_DATA__')?.textContent as string
)
或者你直接用
window.__NEXT_DATA__
也行
嘿嘿!