web-dev-qa-db-ja.com

DomeXception: 'history'に 'replaceState'を実行できませんでした:URLを持つ履歴状態オブジェクト

GoogleでWebページのキャッシュバージョンを開くときに、Reactアプリでエラーが発生しました。

DomeXception: 'history'で 'replaceState'を実行できませんでした:URL 'https:// projectURL'を持つ履歴状態オブジェクトは、原点 'https://webcache.googleusercont.com'とURL 'httpsを持つドキュメントで作成できません。 //webcache.googleusercontent.com/search?cache:x4dz2ukzzayj:https://projecturll/&cd=1&hl=en& ct= clnk& cl = in '

enter image description here

私たちのアプリでは、React-router-DOMと実装されたサーバーサイドレンダリングを使用しています。 Google検索でキャッシュされたオプションを指定してページを開くとき、最初に数秒のページをロードしてから、上記のエラーを使用して空白ページを表示します。

私が見つけた解決策を検索しながら https://github.com/Reacttraining/React -Router/issues/5801 私の問題に関連していますが、解決策はありません。

更新1:

同じ質問が質問されています ここ 、しかし角度のために。私は答えで説明されているものとそれが私の問題に関連しているのか理解できませんでしたが。

Reactアプリのサーバーサイドレンダリングのために React Loadable SSRアドオン を使用しています。

更新2:

サーバーサイドレンダリングに使用されるNPMパッケージのGitリポジトリで同じ問題を開きました。 問題が開かれました

更新3:

Google chrome]で開くとうまく機能します。セキュリティを無効にすると、コードに関連するものではないはずです。

また、Bing Search Engineキャッシュバージョンで開かれたときに異なるエラーが発生します。

スクリプトリソースはリダイレクトの背後にあり、これは許可されていません。

enter image description here

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)が受信されました。

7
Alwaysalearner

「空白ページ」の前に通常のページが表示されるので、最初に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の制限に基づいています。そのうちの1つはhttps://connect.facebook.net/en_US/fbevents.jsから来ています。 Googleの内部の「WebCache」アルゴリズムによって引き起こされるサービスワーカーファイルに関連する404エラーは、これについて何かできるかどうかはわかりません。

とにかく、これらのエラーはキャッシュされたサイトの正しい表示を妨げる​​べきではありません。なぜなら、空白のページが表示されている理由ではありません。私の意見では、もちろんスクリーンショットに基づいています。

1
artanik