页面重新加载后的不同行为(应用程序处于生产模式,由 React 和 Express 制作)

Different behavior after page is reloaded (app is in production mode, made by react and express)

在开发模式下一切正常。乍一看,应用程序在构建模式下是相同的(我在服务器端使用 express)。但是当我尝试刷新我的页面时(url 包含参数)我收到 只有

{
surveyString: "[{"type":"radiogroup","name":"Favorite Character?","title":"Favorite Character?","isRequired":true,"colCount":1,"choices":["Walt","Hank","Jesse","Mike"]},{"type":"radiogroup","name":"Favorite Actor?","title":"Favorite Actor?","isRequired":true,"colCount":1,"choices":["Aaron Paul","Bryan Cranston","Jonathan Banks"]}]",
surveyTitle: "Breaking Bad Survey"
}

这是从服务器发送的响应,这当然是我想要的,但不知何故应用程序没有合并它。

我在 Chrome 中收到的错误是

Not allowed to load local resource: view-source

在 Firefox 中,错误看起来有些不同

Content Security Policy: The page’s settings blocked the loading of a resource a ...resource link...

通过这些错误,我承认了有关内容安全策略、快递包如何克服它的一些基本方法等等……但那是另一回事,我希望我能在反应方面解决问题。

我很乐观,因为我在其他页面上的 href links 有相同的行为。当我用 LinkTo 应用程序替换 aHref 时,工作正常。

我点击link,在新页面上一切正常,直到我刷新。

link 是到 github 页: component which not survives refresh

function SingleSurvey(props) {
  const [complete, setComplete] = useState(false);
  const [voted, setVoted] = useState(false);
  const [json, setJson] = useState({});
  const [title, setTitle] = useState("");
  const [resultsDisplay, setResultsDisplay] = useState(false);

  const { id } = useParams();

  useEffect(() => {
    surveyServices.getSingle(id).then((res) => {
      const stringQuestions = JSON.parse(res.surveyString);
      setJson({ questions: stringQuestions });
      setTitle(res.surveyTitle);
    });
  }, [id]);

  useEffect(() => {
    const checkItem = window.localStorage.getItem(`chartVoted-${id}`);
    if (checkItem) {
      setVoted(true);
    }
    // eslint-disable-next-line
  }, []);

  function onComplete(result) {
    surveyServices.updateVotes({
      data: result.data,
      id,
    });
    window.localStorage.setItem(`chartVoted-${id}`, true);
    setComplete(true);
    setTimeout(() => {
      window.location.reload();
    }, 1100);
  }
  return (
    <main className="survey-page">
      {complete && <p className="survey-finished"></p>}
      {!voted ? (
        <>
          <Survey.Survey
            json={json}
            showCompletePage={false}
            onComplete={(result) => onComplete(result)}
          />
          <div className="show-results">
            <button
              className="btn-results"
              onClick={() => setResultsDisplay(!resultsDisplay)}
            >
              {resultsDisplay ? "Hide Charts" : "Show Charts"}
            </button>
            <div
              className="visible-results"
              style={{ display: resultsDisplay ? "" : "none" }}
            >
              <Result id={id} title={title} />
            </div>
          </div>
        </>
      ) : (
        <div className="just-results">
          <Result id={id} title={title} />
        </div>
      )}
    </main>
  );
}
export default SingleSurvey;

switch routes settings

<Router>
      <Notification />
      <Switch>
        <Route exact path="/api/survey/single/:id" component={SingleSurvey} />
      </Switch>
</Router>

ReactDOM 渲染,我使用的是基本的 redux

<Provider store={store}>
    <App />
</Provider>,

express

app.use(express.static(path.join(__dirname, "build")));
app.use("/api/survey", surveyController);
app.use("/api/users", usersController);
app.use("/api/login", loginController);

app.get("/", function (req, res) {
  app.get("/*", function (req, res) {
    res.sendFile(path.join(__dirname, "build", "index.html"));
  });
});

如果想直接看问题app is uploaded on heroku.

希望不要错过任何有价值的信息。有人知道如何解决令人难以置信的恼人问题吗?

您混淆了您的 API 路由和您的客户端路由,因此导致超载。

当 Web 浏览器访问网站时,它们会发出 GET 请求,这与您与 Express 服务器交互的方式完全相同。

您的问题是您通过将用户重定向到向您的服务器发出 GET 请求的服务器端点,不小心向您的服务器发出了 get 请求。

发生了什么事

  • Url 更改由 Link 组件触发(不在您提供的代码中

  • React Router 匹配 URL 而不会触发 API 请求(这是单页网络应用程序的工作方式) <Route exact path="/api/survey/single/:id" component={SingleSurvey} />

  • 页面刷新 Express 匹配 URL 和 returns API 响应而不是 index.html app.use("/api/survey", surveyController);

解决方案

  • 将您的 client-side 路径更改为:/client/survey

根据 Alex Mckay 的回答,我更改了路线位置

 <Route
    exact
    path="/client/survey/single/:id"
    component={SingleSurvey}
  />

然后修复我服务器端的内容安全策略错误。 这对我来说是一个全新的领域,所以我在控制台中跟踪错误并一一修复。 使用 [helmet-csp] 包是非常直观的过程。

app.use(
  csp({
    directives: {
      defaultSrc: ["'self'"],
      fontSrc: ["https://fonts.googleapis.com/", "https://fonts.gstatic.com"],
      connectSrc: ["'self'", "http://localhost:3005"],
      styleSrc: [
        "'self'",
        "'unsafe-inline'",
        "https://surveyjs.azureedge.net/1.8.0/modern.css",
        "https://fonts.googleapis.com",
        "'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='",
        "'sha256-OTeu7NEHDo6qutIWo0F2TmYrDhsKWCzrUgGoxxHGJ8o='",
      ],
      imgSrc: ["'self'", "http://localhost:3005"],
      scriptSrc: [
        "'self'",
        "unsafe-inline",
        "'sha256-eE1k/Cs1U0Li9/ihPPQ7jKIGDvR8fYw65VJw+txfifw='",
      ],
      objectSrc: ["'none'"],
      upgradeInsecureRequests: [],
    },
    reportOnly: false,
  })
);

我还从我的一个组件中删除了内联样式,因为组件表现得很奇怪

<>
          <Survey.Survey
            json={json}
            showCompletePage={false}
            onComplete={(result) => onComplete(result)}
          />
          <div className="show-results">
            <button
              className="btn-results"
              onClick={() => setResultsDisplay(!resultsDisplay)}
            >
              {resultsDisplay ? "Hide Charts" : "Show Charts"}
            </button>
            {resultsDisplay && (
              <div>
                <Result id={id} title={title} />
              </div>
            )}
          </div>
</>

而且有效。