[英]Uncaught SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL
[英]DOMException: Failed to execute 'replaceState' on 'History': A history state object with URL
在谷歌上打開網頁的緩存版本時,反應應用程序出現以下錯誤。
DOMException: Failed to execute 'replaceState' on 'History': A history state object with URL 'https://projecturl' cannot be created in a document with origin 'https://webcache.googleusercontent.com' and 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:
這里問了同樣的問題,但對於 Angular。 雖然我無法理解答案中解釋的內容以及它與我的問題的關系。
我們正在使用React Loadable SSR Add-on來對我們的 react 應用程序進行服務器端渲染。
更新 2:
在用於服務器端渲染的 npm package 的 Git 存儲庫上打開了相同的問題。 問題已打開
更新 3:
當我通過禁用安全性在谷歌瀏覽器中打開它時,該頁面工作正常。 因此,它不應該與我的代碼有關。
此外,在 bing 搜索引擎緩存版本中打開時會出現不同的錯誤:
腳本資源位於重定向后面,這是不允許的。
在 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;
根組件.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)。
由於您在“空白頁面”之前看到您的正常頁面,我的猜測是,首先,您會看到網站的 SSR 版本,然后在加載腳本后,您會看到“空白頁面”,因為 CORS 限制。
作為一種解決方案,您可以僅為您的域加載腳本,並將 SSR 版本保留給google/bing/yahoo ,而沒有機會加載這些腳本並破壞站點。
答案基於react-loadable-ssr-addon的示例,這里的想法是檢查window.location.origin
與您的域的來源。 否則,只需完全跳過這些文件。
原始示例:
res.send(`
<!doctype html>
<html lang="en">
<head>...</head>
${styles.map(style => {
return `<link href="/dist/${style.file}" rel="stylesheet" />`;
}).join('\n')}
<body>
<div id="app">${html}</div>
${scripts.map(script => {
return `<script src="/dist/${script.file}"></script>`
}).join('\n')}
</html>
`);
這是我的動態加載示例:
res.send(`
<!doctype html>
<html lang="en">
<head>...</head>
${styles.map(style => {
return `<link href="/dist/${style.file}" rel="stylesheet" />`;
}).join('\n')}
<body>
<div id="app">${html}</div>
<script>
function loadScript(url) {
var s = document.createElement("script");
s.src = url; document.body.appendChild(s);
}
if (
window.location.origin === "https://example.com" ||
window.location.origin === "http://localhost" // for development purpose
) {
${scripts.map(script => {
return `loadScript("/dist/${script.file}");`
}).join('\n')}
}
</script>
</html>
`);
當然,你的應用程序中有你自己的代碼,這就是為什么我不能給你一個完整的解決方案。 您應該更改代碼以遵循此想法。
至於其他錯誤。 部分地,它們也基於 CORS 限制,其中之一來自https://connect.facebook.net/en_US/fbevents.js
。 與您的服務工作人員文件相關的 404 錯誤是由 google 的內部“webcache”算法引起的,我不確定您是否可以對此做些什么。
無論如何,這些錯誤不應干擾緩存站點的正確顯示,因為它們不是您看到空白頁面的原因。 在我看來,當然,這是基於截圖。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.