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

news2024/11/25 2:28:11

        使用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-基础示例

        代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>hash模式</title>
    <style>
        .box{
            margin:15px;
            min-height: 100vh;
            width: 100%;
            background-color: skyblue;
        }
    </style>
</head>
<body>

    <div class="box" id="part_1">part_1</div>
    <div class="box" id="part_2">part_2</div>
    <a href="#part_1">to_part_1</a>
    <a href="#part_2">to_part_2</a>

    <script>
        window.onhashchange = (event)=>{
            console.log('hash:',window.location.hash,event)
        }

    </script>
</body>
</html>

example-hash-Router

        模拟简单的hash路由,

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>hash模式</title>
    <style>
        .box {
            margin: 15px;
            min-height: 100px;
            width: 100%;
            background-color: skyblue;
        }
    </style>
</head>

<body>
    <a href="#home">home</a>
    <a href="#part_1">part_1</a>
    <a href="#part_2">part_2</a>
    <div id="app">

    </div>
    <!-- HTML 内容模板(<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以 (原文为 may be) 在运行时使用 JavaScript 实例化。 -->
    <template id="home">
        <div class="box" id="home">home</div>
    </template>
    <template id="part_1">
        <div class="box" id="part_1">part_1</div>
    </template>

    <template id="part_2">
        <div class="box" id="part_2">part_2</div>
    </template>

    <script>
        //根节点
        const rootNode = document.getElementById("app")
        //刷新页面方法
        const refreshApp = (hash) => {
            hash = hash || 'home'
            const elem = document.getElementById(hash);
            rootNode.innerHTML = elem.innerHTML
        }
        //hash-change事件监听
        window.onhashchange = (event) => {
            console.log('hash:', window.location.hash, event)
            //根据hash值显示对应的页面部分
            const hash = window.location.hash.replace("#", '');
            refreshApp(hash)
        }
        //初始事件监听
        document.body.onload = () => {
            const hash = window.location.hash.replace("#", '');
            refreshApp(hash)
        }

    </script>
</body>

</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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>history模式</title>
    <style>
        .box {
            margin: 15px;
            min-height: 100px;
            width: 100%;
            background-color: skyblue;
        }
    </style>
</head>
<body>
    <nav id="nav">
        <a href="javascript:void(0)">home</a>
        <a href="javascript:void(0)">part_1</a>
        <a href="javascript:void(0)">part_2</a>
    </nav>
    <div id="app">

    </div>
    <!-- HTML 内容模板(<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以 (原文为 may be) 在运行时使用 JavaScript 实例化。 -->
    <template id="home">
        <div class="box" id="home">home</div>
    </template>
    <template id="part_1">
        <div class="box" id="part_1">part_1</div>
    </template>

    <template id="part_2">
        <div class="box" id="part_2">part_2</div>
    </template>
    <script>
        //获取节点
        const rootNode = document.getElementById("app")
        const navlement = document.querySelector('#nav')
        //刷新页面方法
        const refreshApp = (path) => {
            path = path || 'home'
            const elem = document.getElementById(path);
            rootNode.innerHTML = elem.innerHTML
        }
        navlement.onclick = (event)=>{
            const target = event.target;
            if(target.nodeName !== 'A'){
                return
            }
            const path = target.textContent
            console.log(path)
            // history.pushState(),改变当前地址栏的路径,并不会更新页面内容
            history.pushState(null,null,path)
            refreshApp(path)
        }
        //onpopstate-事件:监听-点击浏览器的前进按钮/后退按钮
        window.onpopstate = (event)=>{
            console.log(event)
            //
        }

    </script>
</body>
</html>

优缺点

        history 致命的缺点就是当改变页面地址后,强制刷新浏览器时,(如果后端没有做准备的话)会报错,因为刷新是拿当前地址去请求服务器的,如果服务器中没有相应的响应,会出现 404 页面

        例如:拿live-server来讲,保存页面时,导致页面刷新,进而显示找不到页面。

Nginx相关配置

Nginx+History路由模式:404问题

        通常,我们使用nginx部署前端项目时,简单配置如下,

worker_processes  1;
events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    #服务配置
    server {
       listen       8157;
       server_name  localhost;
       
        #前端项目部署配置
        location / {
            root   /home/server_dir/erp/web;
            index  index.html index.htm;
        }
    }
}

        但是,当前端项目使用History路由模式进行打包时,每当我们刷新页面,就会显示404找不到,那么,如何在服务端解决这个问题呢?

相关配置

location:root根目录配置

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

        例如:

location /flv/ {
    root /data/web;
}

         当 root 指令在 location 指令域时,root 设置的是 location 匹配访问路径的上一层目录,样例中被请求文件的实际本地路径为 /data/web/flv/。
        Tips:location 中的路径是否带"/",对本地路径的访问无任何影响。

location:alias虚拟目录配置

        Nginx 中想要配置虚拟目录可以使用 alias 指令,该指令的介绍如下表所示:

        例如:

server{
    listen 8080;
    server_name www.nginxtest.org;
    root /opt/nginx-web/www;
    location /flv/ {
        alias /opt/nginx-web/flv/;
    }

    location /js {
        alias /opt/nginx-web/js;
    }

    location /img {
        alias /opt/nginx-web/img/;
    }
}

        可以用如下命令分别进行访问测试:

curl http://127.0.0.1:8080/flv/
curl -L http://127.0.0.1:8080/js
curl http://127.0.0.1:8080/js/
curl -L http://127.0.0.1:8080/img
curl http://127.0.0.1:8080/img/

        alias 指定的目录是 location 路径的实际目录,其所在 location 的 rewrite 指令不能使用 break 参数。

location:try_files

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

         例如:

location /images/ {
    # $uri存在则执行代理的上游服务器操作,否则跳转到default.gif的location
    try_files $uri /images/default.gif;
}

location = /images/default.gif {
    #expires配置可以控制页面资源在浏览器缓存的时间。在指定事件内再次访问该静态资源,将不再像nginx发送请求,而是直接从浏览器缓存中获取
    expires 30s;
}

解决方案:alias+try_files

        可以将前述部署配置改为,即可解决。

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
       listen       8157;
       server_name  localhost;
        #前端项目部署
        location / {
            # root   /home/server_dir/erp/web;
            alias  /home/server_dir/erp/web/;
            index  index.html index.htm;
            try_files $uri $uri/ /index.html;
        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1444858.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python】网络爬虫与信息提取--requests库

导学 当一个软件想获得数据&#xff0c;那么我们只有把网站当成api就可以 requests库:自动爬取HTML页面&#xff0c;自动网络请求提交 robots协议&#xff1a;网络爬虫排除标准&#xff08;网络爬虫的规则&#xff09; beautiful soup库&#xff1a;解析HTML页面 工具&…

使用Cargo创建、编译与运行Rust项目

在 Rust 开发中&#xff0c;Cargo 是一个非常重要的工具&#xff0c;它负责项目的构建、管理和依赖管理。以下是如何使用 Cargo 创建、编译和运行 Rust 项目的详细步骤。 1. 创建新项目 首先确保你已经在计算机上安装了 Rust 和 Cargo。然后&#xff0c;在命令行中输入以下命…

美比特币ETF持仓跨越20万枚BTC大关,成为华尔街有史以来最受欢迎的ETF!

号外&#xff1a;教链内参2.10《内参&#xff1a;BTC真的存在春节模式吗&#xff1f;》 自SEC在2024年1月份一口气批准了十多支比特币现货ETF之后&#xff0c;机构们“不待扬鞭自奋蹄”&#xff0c;在吸收客户上使出浑身解数&#xff0c;激烈竞争。贝莱德&#xff08;IBIT&…

基于微信小程序的在线课堂的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【Linux】信号保存与信号捕捉处理

信号保存与信号捕捉 一、信号保存1. 信号的发送2. 理解信号保存&#xff08;1&#xff09;信号保存原因&#xff08;2&#xff09;信号保存概念 3. 信号保存系统接口&#xff08;1&#xff09;sigset_t&#xff08;2&#xff09;sigprocmask()&#xff08;3&#xff09;sigpend…

【机器学习】支持向量机(SVM)

支持向量机&#xff08;SVM&#xff09; 1 背景信息 分类算法回顾 决策树 样本的属性非数值 目标函数是离散的 贝叶斯学习 样本的属性可以是数值或非数值目标函数是连续的&#xff08;概率&#xff09; K-近邻 样本是空间&#xff08;例如欧氏空间&#xff09;中的点目标函…

《统计学简易速速上手小册》第9章:统计学在现代科技中的应用(2024 最新版)

文章目录 9.1 统计学与大数据9.1.1 基础知识9.1.2 主要案例&#xff1a;社交媒体情感分析9.1.3 拓展案例 1&#xff1a;电商销售预测9.1.4 拓展案例 2&#xff1a;实时交通流量分析 9.2 统计学在机器学习和人工智能中的应用9.2.1 基础知识9.2.2 主要案例&#xff1a;预测客户流…

CSS基础---新手入门级详解

CSS:层叠样式表 CSS&#xff08;Cascading Style Sheets,层叠样式表&#xff09;&#xff0c;是一种用来为结构化文档添加样式&#xff08;字体、间距和颜色&#xff09;的计算机语言&#xff0c;css扩展名为.css。 实例: <!DOCTYPE html><html> <head><…

自然语言处理(NLP)—— 基本概念

自然语言处理&#xff08;Natural Language Processing&#xff0c;简称NLP&#xff09;是人工智能和语言学领域的一个分支&#xff0c;它涉及到计算机和人类&#xff08;自然&#xff09;语言之间的相互作用。它的主要目标是让计算机能够理解、解释和生成人类语言的数据。NLP结…

二十、K8S-1-权限管理RBAC详解

目录 k8s RBAC 权限管理详解 一、简介 二、用户分类 1、普通用户 2、ServiceAccount 三、k8s角色&角色绑定 1、授权介绍&#xff1a; 1.1 定义角色&#xff1a; 1.2 绑定角色&#xff1a; 1.3主体&#xff08;subject&#xff09; 2、角色&#xff08;Role和Cluster…

树莓派编程基础与硬件控制

1.编程语言 Python 是一种泛用型的编程语言&#xff0c;可以用于大量场景的程序开发中。根据基于谷歌搜 索指数的 PYPL&#xff08;程序语言流行指数&#xff09;统计&#xff0c;Python 是 2019 年 2 月全球范围内最为流行 的编程语言 相比传统的 C、Java 等编程语言&#x…

文章页的上下篇功能是否有必要?boke112百科取消上下篇功能

也不知道是从什么时候开始&#xff0c;我们很多站长的博客网站文章页都会在文末添加上“上一篇”和“下一篇”功能&#xff0c;目的是进行站内SEO优化和方便用户阅读上下篇文章。 boke112百科不管是以前使用的Three主题还是现在使用的YIA主题&#xff0c;刚开始的文章页都是有…

微信,支付宝在线换钱平台系统源码

探索全新、全开源的在线换钱系统源码&#xff0c;它将以前所未有的方式改变您的支付体验。我们为您精心打造了一个集简单易用与安全高效于一身的优质产品&#xff0c;它采用最新的技术开发&#xff0c;为您带来前所未有的便捷与安心。 这款在线换钱系统源码设计直观&#xff0…

【hcie-cloud】【27】华为云Stack网络安全防护

文章目录 前言网络安全概述常见网络攻击类型流量型攻击DDoS单包攻击网络攻击防范 网络安全服务华为云Stack网络防护HCS租户网络纵深防护HCS常用网络安全防护服务对比 云防火墙详述云防火墙&#xff08;CFW&#xff09;- 定义云防火墙&#xff08;CFW&#xff09;- 实现原理云防…

Days28 ElfBoard 板]修改开机动画

1.可能需要安装的库 elfubuntu:~/work/psplash$ sudo apt-get install build-essential libncurses5-dev elfubuntu:~/work/psplash$ sudo apt-get install libtool elfubuntu:~/work/psplash$ sudo apt-get install gettext elfubuntu:~/work/psplash$ sudo apt-get install l…

Linux--基础开发工具篇(2)(vim)(配置白名单sudo)

目录 前言 1. vim 1.1vim的基本概念 1.2vim的基本操作 1.3vim命令模式命令集 1.4vim底行命令 1.5 异常问题 1.6 批量注释和批量去注释 1.7解决普通用户无法sudo的问题 1.8简单vim配置 前言 在前面我们学习了yum&#xff0c;也就是Linux系统的应用商店 Linux--基础开…

Redis核心技术与实战【学习笔记】 - 30.番外篇:Redis学习资料、运维说明及使用规范建议

1.Redis学习资料 虽然前面已经学习了 Redis 理论和技术点&#xff0c;但是如果想要持续提升自己的技术能力&#xff0c;还是需要不断丰富自己的知识体系。本章&#xff0c;给你推荐几本优秀的书籍&#xff0c;以及拓展知识面的其他资料。 1.1 经典书籍 在学习 Redis 时&…

python coding with ChatGPT 打卡第20天| 二叉搜索树:搜索、验证、最小绝对差、众数

相关推荐 python coding with ChatGPT 打卡第12天| 二叉树&#xff1a;理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 python coding with ChatGPT 打卡第15天| 二叉树&#xff1a;翻转…

Python程序一直在window后台进程运行

CMD命令执行方法 windows 后台运行并输出日志文件 命令&#xff1a; python qipa250.py >> qipa250_logs.log 2>&1 & 窗口关闭后程序也就关闭了 windows 前台运行并输出日志文件 命令&#xff1a; pythonw qipa250.py >> qipa250_logs.log 2>&a…

第74讲Breadcrumb 面包屑实现

Breadcrumb 面包屑实现 为了实现二级路由&#xff0c;我们搞成搞个子路由&#xff0c;对于二级菜单 const routes [{path: /,name: 首页,component: () > import(../views/layout),redirect:/home,children:[{path: /home,name: 首页,component: () > import(../views…