Nginx与history路由模式:刷新页面404问题

打印 上一主题 下一主题

主题 1767|帖子 1767|积分 5301

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
        利用nginx摆设前端项目,路由模式接纳history模式时,刷新页面之后,显示404。
路由模式

        前端路由的基本作用为:
        ①当浏览器地址变革时,切换页面;
        ②点击浏览器后退、前进按钮时,更新网页内容;
        ③刷新浏览器页面时,网页加载与当前路由相匹配的内容。
        在前端项目开发中,主要利用到两种路由模式:
        【1】hash模式:通过监听浏览器地址hash值,在回调函数中切换网页内容/部门内容;
        【2】history模式:基于history API自界说url地址,实现url地址变革并保证网页内容的切换。
hash模式

基本原理

        利用window.location.hash属性及窗口的onhashchange事件,可以实现监听浏览器地址hash值变革,执行相应的js切换网页。
      
       Location:hash属性            
       hashchange事件               hash模式的特点如下:
   ①hash指的是地址中#号以及后面的字符,也称为散列值。hash也称作锚点,本身是用来做页面跳转定位的。如http://localhost/index.html#abc,这里的#abc就是hash;
散列值是不会随哀求发送到服务器端的,以是改变hash,不会重新加载页面
③ window 的 hashchange 事件作用:当散列值改变时,可以通过 location.hash 来获取和设置hash值;
④location.hash值的变革会直接反应到浏览器地址栏。
  hash路由触发条件

        那么,如何触发hash路由呢?主要分为编程式触发(例如:通过a标签设置锚点、js代码级动态更新)和手动触发(例如:点击浏览器的前进/后退按钮),
        ①当浏览器地址栏的散列值/hash值变革时,会自动触发location..hash属性值的变革,从而触发onhashChange事件。
        ②当只改变浏览器地址栏URL的哈希值时,按下enter键不会导致浏览器向服务器发送哀求,此时仅仅是设置hash值,并触发onhashChange事件。
        ③HTML提供的a标签,通过其href属性可以为页面设置锚点,当点击a标签时,可以跳转到对应元素所在区域,同时更新地址栏hash值(陪同着Location.hash属性值的更新),并触发onhashChange事件。
example-基础示例

        代码示例:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>hash模式</title>
  7.     <style>
  8.         .box{
  9.             margin:15px;
  10.             min-height: 100vh;
  11.             width: 100%;
  12.             background-color: skyblue;
  13.         }
  14.     </style>
  15. </head>
  16. <body>
  17.     <div class="box" id="part_1">part_1</div>
  18.     <div class="box" id="part_2">part_2</div>
  19.     <a href="#part_1">to_part_1</a>
  20.     <a href="#part_2">to_part_2</a>
  21.     <script>
  22.         window.onhashchange = (event)=>{
  23.             console.log('hash:',window.location.hash,event)
  24.         }
  25.     </script>
  26. </body>
  27. </html>
复制代码

example-hash-Router

        模仿简朴的hash路由,
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>hash模式</title>
  7.     <style>
  8.         .box {
  9.             margin: 15px;
  10.             min-height: 100px;
  11.             width: 100%;
  12.             background-color: skyblue;
  13.         }
  14.     </style>
  15. </head>
  16. <body>
  17.     <a href="#home">home</a>
  18.     <a href="#part_1">part_1</a>
  19.     <a href="#part_2">part_2</a>
  20.     <div id="app">
  21.     </div>
  22.     <!-- HTML 内容模板(<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以 (原文为 may be) 在运行时使用 JavaScript 实例化。 -->
  23.     <template id="home">
  24.         <div class="box" id="home">home</div>
  25.     </template>
  26.     <template id="part_1">
  27.         <div class="box" id="part_1">part_1</div>
  28.     </template>
  29.     <template id="part_2">
  30.         <div class="box" id="part_2">part_2</div>
  31.     </template>
  32.     <script>
  33.         //根节点
  34.         const rootNode = document.getElementById("app")
  35.         //刷新页面方法
  36.         const refreshApp = (hash) => {
  37.             hash = hash || 'home'
  38.             const elem = document.getElementById(hash);
  39.             rootNode.innerHTML = elem.innerHTML
  40.         }
  41.         //hash-change事件监听
  42.         window.onhashchange = (event) => {
  43.             console.log('hash:', window.location.hash, event)
  44.             //根据hash值显示对应的页面部分
  45.             const hash = window.location.hash.replace("#", '');
  46.             refreshApp(hash)
  47.         }
  48.         //初始事件监听
  49.         document.body.onload = () => {
  50.             const hash = window.location.hash.replace("#", '');
  51.             refreshApp(hash)
  52.         }
  53.     </script>
  54. </body>
  55. </html>
复制代码


优缺点



  • 优点:浏览器兼容性较好,连 IE8 都支持
  • 缺点:路径在井号 # 的后面,比力丑
history模式

基本原理|History对象

        history模式基于history API实现。
        history API 是 H5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起哀求。
      
       history API      
        关于History对象,
        ①window.history 属性指向 History 对象,它表示当前窗口的浏览汗青。当发生改变时,只会改变页面的路径,不会刷新页面。
        ②History 对象保存了当前窗口访问过的全部页面网址。通过 history.length 可以得出当前窗口一共访问过几个网址。
        ③由于安全缘故原由,浏览器不允许脚本读取这些地址,但是允许在地址之间导航
        ④浏览器工具栏的“前进”和“后退”按钮,着实就是对 History 对象进行操纵。
history路由触发条件

        每当 history 对象出现变革时,就会触发 popstate 事件。
      
       onpopstate事件               ①仅仅调用pushState()方法或replaceState()方法 ,并不会触发该事件;
        ②只有用户点击浏览器倒退按钮和前进按钮,或者利用 JavaScript 调用History.back()、History.forward()、History.go()方法时才会触发。
        ③别的,该事件只针对同一个文档,假如浏览汗青的切换,导致加载不同的文档,该事件也不会触发。
        ④页面第一次加载的时候,浏览器不会触发popstate事件。
example-history-Router

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>history模式</title>
  7.     <style>
  8.         .box {
  9.             margin: 15px;
  10.             min-height: 100px;
  11.             width: 100%;
  12.             background-color: skyblue;
  13.         }
  14.     </style>
  15. </head>
  16. <body>
  17.     <nav id="nav">
  18.         <a href="javascript:void(0)">home</a>
  19.         <a href="javascript:void(0)">part_1</a>
  20.         <a href="javascript:void(0)">part_2</a>
  21.     </nav>
  22.     <div id="app">
  23.     </div>
  24.     <!-- HTML 内容模板(<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以 (原文为 may be) 在运行时使用 JavaScript 实例化。 -->
  25.     <template id="home">
  26.         <div class="box" id="home">home</div>
  27.     </template>
  28.     <template id="part_1">
  29.         <div class="box" id="part_1">part_1</div>
  30.     </template>
  31.     <template id="part_2">
  32.         <div class="box" id="part_2">part_2</div>
  33.     </template>
  34.     <script>
  35.         //获取节点
  36.         const rootNode = document.getElementById("app")
  37.         const navlement = document.querySelector('#nav')
  38.         //刷新页面方法
  39.         const refreshApp = (path) => {
  40.             path = path || 'home'
  41.             const elem = document.getElementById(path);
  42.             rootNode.innerHTML = elem.innerHTML
  43.         }
  44.         navlement.onclick = (event)=>{
  45.             const target = event.target;
  46.             if(target.nodeName !== 'A'){
  47.                 return
  48.             }
  49.             const path = target.textContent
  50.             console.log(path)
  51.             // history.pushState(),改变当前地址栏的路径,并不会更新页面内容
  52.             history.pushState(null,null,path)
  53.             refreshApp(path)
  54.         }
  55.         //onpopstate-事件:监听-点击浏览器的前进按钮/后退按钮
  56.         window.onpopstate = (event)=>{
  57.             console.log(event)
  58.             //
  59.         }
  60.     </script>
  61. </body>
  62. </html>
复制代码


优缺点

        history 致命的缺点就是当改变页面地址后,强制刷新浏览器时,(假如后端没有做预备的话)会报错,因为刷新是拿当前地址去哀求服务器的,假如服务器中没有相应的响应,会出现 404 页面。
        例如:拿live-server来讲,保存页面时,导致页面刷新,进而显示找不到页面。

Nginx相关设置

Nginx+History路由模式:404问题

        通常,我们利用nginx摆设前端项目时,简朴设置如下,
  1. worker_processes  1;
  2. events {
  3.     worker_connections  1024;
  4. }
  5. http {
  6.     include       mime.types;
  7.     default_type  application/octet-stream;
  8.     sendfile        on;
  9.     keepalive_timeout  65;
  10.     #服务配置
  11.     server {
  12.        listen       8157;
  13.        server_name  localhost;
  14.       
  15.         #前端项目部署配置
  16.         location / {
  17.             root   /home/server_dir/erp/web;
  18.             index  index.html index.htm;
  19.         }
  20.     }
  21. }
复制代码
        但是,当前端项目利用History路由模式进行打包时,每当我们刷新页面,就会显示404找不到,那么,如安在服务端办理这个问题呢?
相关设置

location:root根目次设置

        用户哀求的终极结果是要返回数据,当响应文件在 Nginx 服务器当地时,需要进行当地文件位置、读或写、返回执行结果的操纵。Nginx 中的 root 指令可以设定哀求 URL 的当地文件根目次,如下表所示。

        例如:
  1. location /flv/ {
  2.     root /data/web;
  3. }
复制代码
         当 root 指令在 location 指令域时,root 设置的是 location 匹配访问路径的上一层目次,样例中被哀求文件的实际当地路径为 /data/web/flv/。
        Tips:location 中的路径是否带"/",对当地路径的访问无任何影响。
location:alias假造目次设置

        Nginx 中想要设置假造目次可以利用 alias 指令,该指令的介绍如下表所示:

        例如:
  1. server{
  2.     listen 8080;
  3.     server_name www.nginxtest.org;
  4.     root /opt/nginx-web/www;
  5.     location /flv/ {
  6.         alias /opt/nginx-web/flv/;
  7.     }
  8.     location /js {
  9.         alias /opt/nginx-web/js;
  10.     }
  11.     location /img {
  12.         alias /opt/nginx-web/img/;
  13.     }
  14. }
复制代码
        可以用如下命令分别进行访问测试:
  1. curl http://127.0.0.1:8080/flv/
  2. curl -L http://127.0.0.1:8080/js
  3. curl http://127.0.0.1:8080/js/
  4. curl -L http://127.0.0.1:8080/img
  5. curl http://127.0.0.1:8080/img/
复制代码
        alias 指定的目次是 location 路径的实际目次,其所在 location 的 rewrite 指令不能利用 break 参数。
location:try_files

        try_files 指令是在 Nginx0.7.27 版本中开始加入的,它可以按顺序查抄文件是否存在,并返回第一个找到的文件,假如未找到任何文件,则会调用最后一个参数进行内部重定向,如下表所示:

         例如:
  1. location /images/ {
  2.     # $uri存在则执行代理的上游服务器操作,否则跳转到default.gif的location
  3.     try_files $uri /images/default.gif;
  4. }
  5. location = /images/default.gif {
  6.     #expires配置可以控制页面资源在浏览器缓存的时间。在指定事件内再次访问该静态资源,将不再像nginx发送请求,而是直接从浏览器缓存中获取
  7.     expires 30s;
  8. }
复制代码
办理方案:alias+try_files

        可以将前述摆设设置改为,即可办理。
  1. worker_processes  1;
  2. events {
  3.     worker_connections  1024;
  4. }
  5. http {
  6.     include       mime.types;
  7.     default_type  application/octet-stream;
  8.     sendfile        on;
  9.     keepalive_timeout  65;
  10.     server {
  11.        listen       8157;
  12.        server_name  localhost;
  13.         #前端项目部署
  14.         location / {
  15.             # root   /home/server_dir/erp/web;
  16.             alias  /home/server_dir/erp/web/;
  17.             index  index.html index.htm;
  18.             try_files $uri $uri/ /index.html;
  19.         }
  20.     }
  21. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

温锦文欧普厨电及净水器总代理

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表