【发布时间】:2020-11-16 18:34:07
【问题描述】:
在 Google 上打开网页的缓存版本时,React 应用程序出现以下错误。
DOMException:无法在“历史”上执行“replaceState”:历史 无法在 URL 中创建具有 URL 'https://projecturl' 的状态对象 具有源“https://webcache.googleusercontent.com”和 URL 的文档 'https://webcache.googleusercontent.com/search?q=cache:X4dz2ukZZAYJ:https://projecturl/+&cd=1&hl=en&ct=clnk&gl=in'
在我们的应用程序中,我们使用 react-router-dom 并实现了服务器端渲染。在谷歌搜索中打开带有缓存选项的页面时,它首先加载页面几秒钟,然后在控制台中显示带有上述错误的空白页面。
在寻找解决方案时,我发现了https://github.com/ReactTraining/react-router/issues/5801 与我的问题有关,但没有解决方案。
更新 1:
here 提出了同样的问题,但针对 Angular。 虽然我无法理解答案中的解释以及它与我的问题有何关系。
我们正在使用React Loadable SSR Add-on 为我们的 React 应用程序进行服务器端渲染。
更新 2:
在用于服务器端渲染的 npm 包的 Git repo 上打开了相同的问题。 Issue opened
更新 3:
当我通过禁用安全性在谷歌浏览器中打开它时,该页面工作正常。因此它不应该与我的代码有关。
此外,在必应搜索引擎缓存版本中打开时会出现不同的错误:
脚本资源位于重定向后面,这是不允许的。
在 bing 和 yahoo 搜索引擎上,404 页面以缓存版本出现。
更新 4:
这是路由文件的外观:
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Loadable from 'react-loadable';
import {
OTPNew,
LoginNewFb,
OnboardingWrapper,
PageNotFound,
SignUpSpecialty,
SignUpDetails,
Feed,
} from './lazy';
const RootComponent = Loadable({
loader: () =>
import(/* webpackChunkName: "rootcomp" */ '../components/RootComponent'),
loading: () => null,
modules: ['../components/RootComponent'],
webpack: () => [require.resolveWeak('../components/RootComponent')],
});
const signupRoutes = [
{
path: '/login/otp',
component: OTPNew,
},
{
path: '/login',
component: LoginNewFb,
},
{
path: '/signup/details',
component: SignUpDetails,
},
{
path: '/signup',
component: SignUpSpecialty,
},
];
const Routes = () => {
return (
<Switch>
{signupRoutes.map(sRoute => (
<Route
key={sRoute.path}
path={sRoute.path}
render={routeProps => (
<OnboardingWrapper>
<sRoute.component {...routeProps} />
</OnboardingWrapper>
)}
/>
))}
<Route path="/feed" component={Feed} />
<Route path="/" component={RootComponent} />
<Route path="*" component={PageNotFound} />
</Switch>
);
};
export default Routes;
RootComponent.js
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import { useSelector } from 'react-redux';
import MainComponent from './MainComponent';
import { DiscussionComponent, HomePage, PageNotFound } from '../routes/lazy';
import { useIsMobile } from '../actions/VerifyMobileAction';
import rootRoutes from '../routes/rootRoutes';
import quizRoutes from '../routes/quizRoutes';
import { parseQueryParameter, getAPIHost } from '../helpers/helperFunctions';
function cacheQueryParser(query, projectCanonnicalAddr) {
return query
.split(projectCanonnicalAddr)
.pop()
.split('+')[0];
}
function getPageOrNotFound(location) {
const queryObject = parseQueryParameter(location.search);
const projectCanonnicalAddr = getAPIHost();
if (
location.pathname === '/search' &&
'q' in queryObject &&
queryObject.q.indexOf('cache') === 0 &&
queryObject.q.indexOf(projectCanonnicalAddr) > -1
) {
const replacer = cacheQueryParser(queryObject.q, projectCanonnicalAddr);
return {
ComponentRender: null,
replacer,
};
}
return {
ComponentRender: PageNotFound,
replacer: null,
};
}
const RootComponent = () => {
const { OtpVerified } = useSelector(store => store.authenticationReducer);
const isMobileViewport = useIsMobile();
function logicForHomeRoute() {
if (OtpVerified) {
return {
component: DiscussionComponent,
};
}
return {
renderHeaderDesktop: false,
renderHeaderMobile: false,
renderFooter: false,
renderSideProfile: false,
component: HomePage,
};
}
const typeOfAppClassName = `${
isMobileViewport ? 'mobile' : 'desktop'
}-viewport-app`;
return (
<div className={typeOfAppClassName}>
<Switch>
<Route
exact
path="/"
render={() => <MainComponent {...logicForHomeRoute()} />}
/>
{[...quizRoutes, ...rootRoutes].map(sRoute => (
<Route
key={sRoute.path}
path={sRoute.path}
render={props => {
const { location, history } = props;
if (sRoute.path === '/:alternate_username') {
if (location.pathname.startsWith('/dr') === false) {
const { replacer, ComponentRender } = getPageOrNotFound(
location
);
if (ComponentRender) {
return <ComponentRender />;
}
history.replace(replacer);
return null;
}
}
return <MainComponent {...props} {...sRoute} />;
}}
/>
))}
</Switch>
</div>
);
};
export default RootComponent;
更新 5
控制台显示另一个错误:
获取脚本时收到错误的 HTTP 响应代码 (404)。
【问题讨论】:
-
您介意分享您的代码吗?
-
似乎您正试图将完整的网址推送到历史记录。
-
@SonuBamniya,我不确定我应该分享哪一部分代码来调试这个问题
标签: reactjs react-router react-router-dom server-side-rendering