我有一個在客戶端和服務器上呈現的React應用程序。當任何組件的render()失敗時(由於我的代碼中存在一個錯誤,例如試圖讀取一個未定義對象的屬性),那麼如果我從瀏覽器中的另一個頁面導航,那麼我會得到一個完整的堆棧跟蹤瀏覽器開發者控無法在React服務器端渲染中處理UnhandledPromiseRejectionWarning
然而,當我觸發一個服務器端渲染相同的代碼(直接將瀏覽器指向包含有故障的部件有問題的路線),然後我就得到這樣的錯誤,這些在服務器的控制檯:
(node:97192) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'tagDefinitionId' of undefined
不帶堆棧跟蹤,這是一個有點難以調試。
問題:有沒有辦法來毯包羅萬象的渲染()失敗時的服務器端渲染?
觸發服務器端響應於被請求的節點Express端點呈現的代碼如下。我相信在renderToString()內發生未處理的承諾拒絕,但是這個函數返回一個字符串,而不是一個承諾。
`
import configureStore from '../../redux/store';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import React from 'react';
import RouterContext from 'react-router/lib/RouterContext';
import createMemoryHistory from 'react-router/lib/createMemoryHistory';
import match from 'react-router/lib/match';
import template from './template';
import routes from '../../routes';
const clientAssets = require(KYT.ASSETS_MANIFEST);
app.use((request, response) => {
const history = createMemoryHistory(request.originalUrl);
match({ routes, history }, (error, redirectLocation, renderProps) => {
if (error) {
response.status(500).send(error.message);
} else if (redirectLocation) {
response.redirect(302, `${redirectLocation.pathname}${redirectLocation.search}`);
} else if (renderProps) {
// This is the initial store
const store = configureStore();
// When a React Router route is matched then we render
// the components and assets into the template.
const render =() => {
// Grab the initial state from our Redux store
const initialState = JSON.stringify(store.getState());
let isNotFoundRoute = false;
if (renderProps.routes[1].path === '*') {
isNotFoundRoute = true;
}
// Populate the HTML document with the current redux store
response.status(isNotFoundRoute ? 404 : 200).send(template({
root: renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
),
cssBundle: clientAssets.main.css,
jsBundle: clientAssets.main.js,
initialState,
}));
};
// Fetch the components from the renderProps and when they have
// promises, add them to a list of promises to resolve before starting
// a HTML response
fetchComponentData(store.dispatch, renderProps.components, renderProps.params).then(render);
} else {
response.status(404).send('Not found');
}
});
});
`
我想自定義代碼可能與此有關的唯一進口是template.js:
`
import Helmet from 'react-helmet';
export default (vo) => {
const helmet = Helmet.rewind();
return `
<!DOCTYPE html>
<html lang="en" ${helmet.htmlAttributes.toString()} >
<head>
${helmet.title.toString()}
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta charSet='utf-8' />
<meta httpEquiv="Content-Language" content="en" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="white" />
${helmet.meta.toString()}
${helmet.link.toString()}
<link id="favicon" rel="shortcut icon" href="/favicon.png" sizes="16x16 32x32" type="image/png" />
<link rel="manifest" href="manifest.json">
${vo.cssBundle ? '<link rel="stylesheet" type="text/css" href="' + vo.cssBundle + '">' : ''}
</head>
<body ${helmet.bodyAttributes.toString()} >
<div id="root" class="root"><div>${vo.root}</div></div>
<script>
window.__PRELOADED_STATE__ = ${vo.initialState}
</script>
<script async src="${vo.jsBundle}"></script>
</body>
</html>
`;
};
`
如何只處理錯誤,而不是讓它未處理? '.then(render).catch(err => {console.error(err); response.status(500).send(「sorry,we're looking into it」)})? – Bergi
是的,[還有一個全面的](https://nodejs.org/api/process.html#process_event_unhandledrejection),你可以用它來記錄你的堆棧痕跡 – Bergi
...我以爲我試過沒有成功...但你的第一個建議工作得很好。你可以提交這個答案,我可以接受嗎? – womblbombl