React-Router 刷新后报错 or Cannot GET /detail

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zwkkkk1/article/details/83411071

这是今天自己随便鼓捣 React-Router 的官方 demo 所遇到的问题,具体表现是:'/' 根节点 Home 显示无误,不过其他任何路由 例如 /detail,均显示 Cannot GET /detail

在我反复确认 js 代码与官方给出的代码一致后,我开始从 webpack 寻找答案。

果然很快,我就找到类似的问题:

React-router v4 - cannot GET url
React-router urls don’t work when refreshing or writting manually

虽然他们的问题普遍表现在:第一次访问页面是好的,但是在刷新或者手动输入路由地址时,会报 Cannot GET /detail

所幸我照着他们的解决方案也改好了我的 bug

方案1

将 demo 中用的 BrowserRouter 改为 HashRouter 即可

你需要注意的是:

比如你的路由设置为 /detail,原来访问 localhost:8080/detail,在改成 HashRouter 之后,可能需要访问 localhost:8080/#/detail

方案2

修改 webpack.config.js 配置文件

module.exports = {
    // 省略其他的配置
    devServer: {
        historyApiFallback: true
    }
}

devServer 中必须设置 historyApiFallback: true

找寻原因

至于为何会出这个问题呢,这里有一篇文章讲的非常好,我这边做个大概的总结加翻译吧(可能不是很贴切,毕竟英语捉鸡,有兴趣的同学可以直接移步 传送门1 传送门2

首先我们需要知道 React-Router 这类前端路由被称为 client-side routers(后面简称 CSR 吧)。此外,在引入 CSR 后,目前会有两个地方(浏览器、服务端)会进行 URL 解析的工作,在以前浏览器会直接发送一个 GET request 给服务端,服务端做 URL 解析的工作

了解完上面的知识点后,我们先来分析一次正确的 CSR 解析过程。

  1. 浏览器在访问页面(比如首页 "/")之前,客户端还没有加载任何的 js 代码,意味着也没有 React、React Router,所以首次的 GET request 都会被发送到服务端;

  2. 服务端在解析 URL 之后,会返回包含需要的 js 代码的页面,其中就有 React、React Router 等等,首页加载完成

  3. 打个比方,用户点击了首页导航栏中的 About us 按钮,URL 修改成了 http://example.com/about(CSR 会调用 history.pushState 这个浏览器 API 仅在浏览器本地修改了 URL) —— 没有请求发送到服务端没有页面刷新!(因为在第2步后,CSR 已经加载完成,承担了解析 URL 的工作)

所以基本上当你点击了一个跳转按钮,一些 JavaScript 代码运行控制地址栏中的 URL 发生变化(没有页面刷新)。

那么如果手动进行了刷新或是手动输入地址,此时程序会再次绕过 React、React Router 的代码,发送 GET request 到服务端,如果你的服务端没有设置对应的路由可以解析这个 URL,那它就会返回 Cannot GET。尽管相同的 URL 会在客户端是可以正常运行的,那是 React Router 在解析 URL

下面我们来看看上面给的两种解决方案为何可以生效,以及各自的缺陷

Hash Router

Browser Router 改为 Hash Router,页面的 URL 会变为 http://example.com/#/about。在 hash 标志符(#)之后的部分不会被发送到服务端,服务端只能接收到 http://example.com,返回首页以及包含 React、React Router 的 JS 代码。然后 CSR 代码生效,会解析 #/about,并呈现正确的页面。

缺点

  1. 因为 URL 都会自动添加一个 #,不是很好看
  2. 使用此方法将不能使用服务器渲染

historyApiFallback

webpack 手册

进行这项配置是告诉 Webpack Dev Server,当使用 HTML History API(history.pushState) 时,任意的 404 响应都会被重定向到 /index.html

缺点

  1. 只适合开发环境中进行配置

有时候配置了 historyApiFallback 可能会出现下面这样的问题

在这里插入图片描述

这个问题需要配置 webpack.config.js 中的

module.exports = {
    output: {
        publicPath: '/'
    }
}

publicPath 配置的值需要与你的 index.html 引入的 src 对应:

<script type="text/javascript" src="/app.bundle.js"></script>

下面附一份我的 webpack 配置文件,大家可以根据自己的项目情况进行修改

var path = require('path')

module.exports = {
  entry: './src/app.js',
  output: {
    path: path.join(__dirname, './build'),
    filename: 'app.bundle.js',
    publicPath: '/'
  },
  mode: 'development',
  module: {
    rules: [
      { test: /\.js$/, use: 'babel-loader'},
      { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }
    ]
  },
  devServer: {
    historyApiFallback: true
  }
}
展开阅读全文

javax.servlet.ServletException: Cannot get value for expression

04-13

访问页面时出现这样的错误:rnjavax.servlet.ServletException: Cannot get value for expression '#areaBean.secArea.areaId'rn javax.faces.webapp.FacesServlet.service(FacesServlet.java:121)rn org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:174)rn org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)rn org.apache.myfaces.component.html.util.ExtensionsFilter.doFilter(ExtensionsFilter.java:122)rnrnrnroot cause rnrnjavax.faces.FacesException: Cannot get value for expression '#areaBean.secArea.areaId'rn org.apache.myfaces.context.servlet.ServletExternalContextImpl.dispatch(ServletExternalContextImpl.java:421)rn org.apache.myfaces.application.jsp.JspViewHandlerImpl.renderView(JspViewHandlerImpl.java:234)rn org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)rn org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:216)rn org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:348)rn javax.faces.webapp.FacesServlet.service(FacesServlet.java:107)rn org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:174)rn org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)rn org.apache.myfaces.component.html.util.ExtensionsFilter.doFilter(ExtensionsFilter.java:122)rnrnrn因为我的用户验证还没做好,所以我想直接访问AreaManage.jsp页面,它报错说:得不到areaId的值,这个值是一项输入值,用于查询,我连页面都没进去,当然没有这个值了。所以我想问下 如何直接访问areaManage.jsp 该页面有list 是不是意味着访问这个页面时就要查询一下数据库 这个应该怎么做??rnrn 论坛

没有更多推荐了,返回首页