簡體   English   中英

DOMException:無法在“歷史”上執行“replaceState”:歷史 state object 與 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM