前言

本来只是想学习 React-Router v6 ,没有想到,带出了这么多东西。前后端路由有什么区别?SPA与MPA的是什么?在了解到前端路之后又发现单页面于应用与多页面应用的不同之处,以及 .nextjs 数据抓取选择CSR、SSR、SSG、ISP不同形式也是有区别的。

lesson1-前端路由介绍


  • 路由来源

路由这个概念最早出现在后端,在服务端中路由描述的是 URL 与处理函数之间的映射关系。对于服务器来说,当接收到客户端发来的HTTP请求,就会根据所请求的相应URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。(该过程又称之为后端路由或 服务端路由
大致流程如图所示:

早期前端路由主要呈现的是多页面应用(MPA)的形式,每个HTML界面通过自己独有的URL,向服务端发起请求。这导致用户每发起一次不同的请求,服务器就要解析不同的URL,切换资源加载慢影响用户体验。
而随着前后端的分离,AJAX的出现带来了无刷新加载的优势。现在的前端路由不同于传统路由,它不在需要服务器解析,而是通过 Hash 函数或者 History API 来实现。在前端开发中,我们可以使用路由设置访问路径,并根据路径与组件的映射关系切换不同的组件,而这个过程都是在同一个页面中实现的,不涉及HTML页面之间的跳转,这也就是我们常说的单页应用(SPA)。
AJAX工作大致流程如图所示:

  • 前后端路由的明显区别

前端路由:不向后台发送请求,不刷新页面,前后端分离( 无刷新加载
后端路由:向服务器发送请求,会刷新页面,前后端不能分离( 需要刷新加载 )

lesson2-简述SPA与MPA


  • 单页面应用与多页面应用模板对比图


SPA 是什么?


SPA全称(single-page application),翻译过来就是单页应用。

单页应用(SPA):它是一种特殊的web应用。将所有的活动局限于一个Web页面中,仅在该Web页面初始化时加载相应的HTML、JavaScript和CSS。 一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转。取而代之的是利用JavaScript动态的变换HTML的内容, 从而实现UI与用户的交互。(该过程就类似我们常说的客户端渲染,又称 CSR

大致CSR 流程图


相对于MPA而言SPA的优缺点是什么?


SPA.优点:

  1. 不涉及html页面跳转,内容改变不需要重新加载页面,可减小服务器压力。
  2. 只涉及组件之间的切换,因此跳转顺畅,用户体验好。
  3. 组件开发更便捷,页面效果更好更炫酷(比如组件切换时的转场动画)。

SPA.缺点:

  1. 单页资源庞大,导致首屏(首页)加载过慢。【面试题-如何解决首屏加载过慢】
  2. 不利于搜索引擎优化(SEO)
  3. 页面复杂度提高,防护数据端点要求更高。更容易受到黑客攻击,因为它们运行在JavaScript上,而JavaScript不执行代码编译,因此更容易受到恶意软件的攻击。

MPA是什么?

MPA全称(mutiple-page application),翻译过来就是多页面应用。

多页面应用(MPA):每个页面都是相对独立的,它们都拥有各自独立的URL,当我们访问一个页面时,需要重新加载公共资源文件(HTML、Javascript、CSS)。
即当MPA对您的输入作出反应或必须显示一些新内容时,它会从服务器请求一个新的HTML页面。在接收到标记之后,浏览器将呈现新页面,并重新加载它。(该过程类似我们常说的服务端渲染,又称 SSR

大致SSR流程图


相对于SPA而言MPA的优缺点是什么?


MPA.优点:

  1. 单独页面对数据端点保护更好。
  2. 更易于搜索引擎优化(SEO)。

MPA缺点:

  1. 需要页面跳转,服务器资源消耗大。
  2. 用户体验要求高,维护难度高。
  3. 依赖URL请求,页面请求反应速度慢。

总体来说:不难发现其实spa与mpa之间的优缺点都是互补的,你的缺点就是我的优点。


SPA与MPA的主要区别是什么?

疑问:SPA 这么好是不是MPA就没有使用了呢?如果有那么什么情况下会使用到 MAP ?
其实从以下几个方面不难看出它们之间的区别,以及选择什么合适。

  • 速度
    速度是这里的一个重要因素——人们的注意力持续时间越来越短,为什么我们对SPA的加载速度越来越没有耐心? 因为它只加载一次大部分的应用资源。每当用户请求新数据时,页面不会完全重新加载。MPA速度较慢,因为每当用户想要访问新数据或移动到网站的不同部分时,浏览器必须从头重新加载整个页面。一个网站的最佳加载时间是0.4秒。如果你的网站或应用程序过于注重图片,那么选择SPA是一个更安全的选择。
  • 耦合性
    SPA是强解耦的,这意味着前端和后端是分离的。单页应用程序使用服务器端开发人员开发的apl来读取和显示数据。在MPA中,前端和后端更加相互依赖。所有的代码通常都包含在一个项目中。
  • 用户体验
    良好的用户体验不再是一种选择,而是一种需求。SPA对移动设备更友好,这一点值得记住,因为很多流量来自移动设备。甚至谷歌也开始将移动体验置于桌面体验之上。在SPA开发中应用的框架使您能够开发移动应用程序。另一方面,MPA支持更好的信息体系结构。您可以根据需要创建任意多的页面,并且可以在一个页面上包含任意多的信息,而不受任何限制。导航是清晰的,所以用户可以很容易地找到他们在网站上的路,这对他们的体验有积极的影响。
  • 安全性
    这可能对你来说并不奇怪,但网站越大,在多页面应用程序中需要付出的努力就越多。如果你想要一个MPA,那么你必须保护每一个网页。在SPA中,要保持页面安全,您所要做的就是更快地保护数据端点,但不一定更安全。SPA更容易受到黑客攻击,因为它们运行在JavaScript上,而JavaScript不执行代码编译,因此更容易受到恶意软件的攻击。
  • 开发过程
    SPA的最大优势之一是可重用的后端代码。如果您认为可重用代码等于更少的工作,那么您是对的。你可以将你在网页应用中使用的代码应用到你的原生移动应用中。这是一个重要的信息,因为应用程序和网站经常在移动设备上使用——这并不奇怪,因为我们大多数人都在不停地奔跑。由于前端和后端划分清晰,可以同时开发这两个部分,加快了整个开发过程。MPA的开发时间较长,因为在大多数情况下,必须从一开始就对服务器端进行编码。
    对JavaScript的依赖
    SPA与JavaScript息息相关。越来越多的搜索引擎开始支持JavaScript,但结果却不尽相同。支持的级别很大程度上取决于所使用的JS框架。如果应用运行在禁用JavaScript的浏览器上,它可能会导致应用功能问题,这可能会导致更高的反弹率和更低的转化率。对JavaScript的依赖也导致了SEO优化和安全问题。可以在不依赖任何JavaScript的情况下构建MPAs。
  • 综上:
    无论是SPA还是MPA ,它们在架构上没有一个是完美的——都有各自的优点和缺点。SPA在速度和代码可重用性方面胜出,这可以用于开发您的移动应用程序,但它在SEO优化方面有不足。使用MPA将帮助可以提高搜索引擎优化(SEO),并且具有更强的可伸缩性,但比SPA慢得多。SPA更好地用于社交网络应用程序、SaaS平台——任何SEO排名不易被破坏者的地方。MPA最适合用于电子商务应用程序、企业目录和市场。如果您是一家提供各种产品的大公司,那么MPA是您的最佳选择。

lesson3-关于CSR、SSR、SSG、ISP


在了解到SPA与MPA后,发现其与渲染模式是息息相关于的。

  • CSR 全称(Client-Side Rendering) 客户端渲染
  • SSR 全称(Server-Side Rendering) 服务器端渲染
  • SSG 全称(Static Site Generator )静态站点生成器
  • ISR 全称(Incremental Static Regeneration) 增量静态再生

1.CSR 全称(Client-Side Rendering) 客户端渲染:在每次渲染之后获取数据

页面的渲染其实就是浏览器将HTML文本转化为页面帧的过程。而如今我们大部分WEB应用都是使用 JavaScript 框架(Vue、React、Angular)进行页面渲染的,也就是说,求在执行 JavaScript 脚本的时候,HTML页面已经开始解析并且构建DOM树了,JavaScript 脚本只是动态的改变 DOM 树的结构,使得页面动态渲染。这个过程就叫客户端渲染。
CSR大致流程如图


SSR 全称(Server-Side Rendering) 服务器端渲染:在每次渲染之前获取数据

服务端渲染就是在浏览器请求页面URL时,服务端直接将我们需要的HTML文本组装好,并返回给浏览器,这个HTML文本被浏览器解析之后,不需要经过JavaScript脚本的执行,可直接构建出完整的DOM树并展示页面中。这个服务端组装的过程,叫做服务端渲染
而从服务器端请求URL获取数据的过程,是在页面加载之前完成的,该过程将首先运行特殊函数映射相关数据,并返回给客户端。在返回前存在一定(映射)延迟。

SSR大致流程图


SSG 全称(Static Site Generator )静态站点生成器:在构建时获取一次数据
解析是在构建时执行的,当发出请求时,html 将静态存储,直接发送回客户端。

ISR 全称(Incremental Static Regeneration) 增量静态再生:
数据在构建时获取一次,在一定冷却时间后再次获取,并在第二次访问时提供。
增量静态再生是SSG和SSR的组合,它是静态服务的,但在特定的时间和条件下,页面将重新构建并再次从API获取数据


参考&学习

  • 介绍参考:https://www.mybj123.com/13984.html
  • 流程图参考:https://juejin.cn/post/7023932512363610120
  • SEO优化参考:https://theodorusclarence.com/blog/nextjs-fetch-usecase
  • 详细案例说明参考:https://theodorusclarence.com/blog/nextjs-fetch-method

lesson4-如何实现前端路由(SPA)


在了解SPA后不难发现其实它的原理是通过以下两种模式来实现的

  • Hash 模式
  • History API 模式

关于 Hash

早起的前端路由实现就是基于location.hash来实现的,location.hash就是路由#后面的内容,其原理就是通过hashchange监听#后面的内容的变化来进行页面更新。hash模式是利用浏览器不会对#后面的路径对服务端发起请求。

Hash 主要特性:

  • 改变hash值,浏览器不会重新加载页面
  • 当刷新页面时,hash不会传给服务器

根据它的特性可以用原始的JS来实现Hash路由

实现思路:运用hash特性,通过触发 hashchange 事件实现界面(UI),更新到 #/后面对应的内容

原生JS实现Hash路由方法

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>原生JS实现的前端路由</title>
</head>
<body><ul><li><a href="#/home">首页</a></li><li><a href="#/user">用户中心</a></li><li><a href="#/login">登录</a></li></ul><div id="view"></div>
</body><script>let view = null// 1.当初始的 HTML 文档被完全加载和解析完成之后,**DOMContentLoaded **事件被触发window.addEventListener('DOMContentLoaded',onload) // 3.监听hash变化window.addEventListener('hashchange',onHashChange)// 2.初次赋值function onload(){view = document.getElementById('view')onHashChange()}function onHashChange(){switch (location.hash){case '#/home':view.innerHTML = '首页'break;case '#/user':view.innerHTML = '用户中心'break;case '#/login':view.innerHTML = '登录'break;}}</script>
</html>

关于 history API

history 提供了 pushStatereplaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新。 history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:

  • 通过浏览器前进后退改变 URL 时会触发 popstate 事件
  • 通过pushState/replaceState或a标签改变 URL 不会触发 popstate 事件。

那应该怎样才能触发popstate事件呢?

  • 方式一:可以拦截 pushState/replaceState的调用和a标签的点击事件来检测 URL 变化。
  • 触发方法思路参考如下图:


原生 history APi 实现案例

<p id="example"><a href="/name" title="name">name</a><a href="/age" title="age">age</a>?
</p>
<div class="main" id="main"></div>
<script>
;(function(){var examplebox = document.getElementById('example')var mainbox = document.getElementById('main')examplebox.addEventListener('click', function(e){e.preventDefault()var elm = e.targetvar uri = elm.hrefvar tlt = elm.titlehistory.pushState({path:uri,title:tlt}, null, uri)mainbox.innerHTML = 'current page is '+tlt})window.addEventListener('popstate',function(e){var state = e.statemainbox.innerHTML = 'current page is ' + state.title})
})()
</script>

在React 与 Vue 中的History模式


Vue中的History 模式

核心思想:通过改变URL来触发pushState事件,达到同步页面UI的目的

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><h1>Vue中的History 模式的实现</h1><button id="myBtn">改变Url</button><script>const myBtn = document.getElementById('myBtn')window.addEventListener('DOMContentLoaded', () => {console.log('path:', location.pathname);})myBtn.addEventListener('click', () => {const state = {'page_id': 1,'user_id': 5}const title = 'gotoser'const url = 'index.html' //切换到的另一个 HTML文件history.pushState(state, title, url)console.log('切换到了路由:', 'user');})window.onpopstate = (e) => {console.log('onpopstate', e.state, location.pathname);}</script>
</body>
</html>
  • 在点击按钮改变URL 之后触发 pushState 事件
  • 当执行返回与前进时触发 **onpopstate ** 事件

最终效果如图:


React-Router中的History模式

在react-router-dom中直接引入 HashRouter 即可

import { HashRouter as Router,Routes,Route,Link } from 'react-routerimport HomePage from './pages/HomePage/index';
import UserPage from "./pages/UserPage/index"
import LoginPage from "./pages/LoginPage/index"function App() {return (<div className="App"><Router><Link to="/">首页</Link><Link to="/user">用户中心</Link><Link to="/login">登录</Link></Router></div>);
}

React-router 原生写法待完善…


BrowserRouter 与 HashRouter 对比

  1. HashRouter 是不需要服务端渲染的,靠浏览器的 # 来区分 path 就可以,而BrowserRouter 需要服务器端对不同的URL返回不同的HTML。需要后端配置

  2. BrowserRouter 使用 HTML5 History API 其中包含 pushState、replaceState 、popstate 等事件,让页面UI同步与之URL。

  3. HashRouter 不支持 location.key 与 location.state 动态路由跳转需要通过 ?传递参数。

  4. HashRouter在web浏览器中使用,当URL由于某种原因不应该(或不能)发送到服务器时。这可能发生在某些共享托管场景中,您无法完全控制服务器。在这些情况下,HashRouter
    可以将当前位置存储在当前URL的散列’部分,因此它永远不会被发送到服务器。所以事件开发环境中不推荐使用。


参考&学习

SPA实现原理参考:https://github.com/youngwind/blog/issues/109


结语:

本文内容主要是学习笔记总结,内容来源于网络

【前端路由原理--原生JS实现方式】--前后端路由的区别、关于单页面应用与多页面应用、什么是CSR、SSR、SSG、ISP相关推荐

  1. 解答网友提问 | 使用VS2022快速生成React/Angular/Vue.js + Web API前后端集成项目

    前言 上次发表了<一键生成Vue.js + Web API前后端集成项目>后,有多位网友来问,有不有其他的前后端集成模板: 实际上,VS2022没有提供前后端集成项目模板. 但是,使用VS ...

  2. 一键生成Vue.js + Web API前后端集成项目

    前言 默认情况下,Visual Studio提供了"基于Vue.js Web 应用程序"项目模板,可以生成Vue.js前端项目. 你需要另外创建Web API项目,调试时需要同时启 ...

  3. 3分钟搞懂前后端开发的区别

    上周末见了好多开发的年轻朋友,问了我一个问题:"前后端的区别和要求是什么?"分不清前后端开发的区别和要求,一种是因为前后端都了解,号称"全栈工程师",但又什么都 ...

  4. 令人惊叹的前端路由原理解析和实现方式

    在单页应用如此流行的今天,曾经令人惊叹的前端路由已经成为各大框架的基础标配,每个框架都提供了强大的路由功能,导致路由实现变的复杂.想要搞懂路由内部实现还是有些困难的,但是如果只想了解路由实现基本原理还 ...

  5. reactrouter监听路由变化_一篇文章搞懂前端路由原理解析和实现方式

    在单页应用如此流行的今天,曾经令人惊叹的前端路由已经成为各大框架的基础标配,每个框架都提供了强大的路由功能,导致路由实现变的复杂. 想要搞懂路由内部实现还是有些困难的,但是如果只想了解路由实现基本原理 ...

  6. html五子棋游戏制作原理,原生JS+Canvas实现五子棋游戏

    功能模块 先看下现在做完的效果: 代码详解 人机对战功能实现 从效果图可以看到,棋盘的横竖可以放的位置为15*15,通过canvas画棋盘: //绘画棋盘 var drawChessBoard = f ...

  7. js 获得明天0点时间戳_Python 3+Django 3 结合Vue.js框架构建前后端分离Web开发平台实战...

    点击上方"测试开发技术",选择设为"设为星标" 优质文章,第一时间送达! 学习全文大概需要 12分钟,内容实战性较强. 1. 前言 本篇将基于Python 3. ...

  8. 阿里云轻量应用服务器部署Node.js+React+MongoDB前后端分离项目

    最近用阿里云服务器部署了一个前端React,后端Node.js(Koa2),数据库MongoDB的前后端分离项目,其间踩了不少的坑,用这篇文章记录一下具体的步骤,希望对你们能有帮助. 1. 服务器的选 ...

  9. 一个后端程序员如何被公司逼的开始写前端代码!奉劝各位最好选择前后端分离的公司...

    hello~各位读者好,我是鸭血粉丝(大家可以称呼我为「阿粉」),在特殊的日子里,大家要注意安全,尽量不要出门,无聊的话,就像阿粉一样,把时间愉快的花在学习上吧. 事情起因 阿粉自从学会Java以来, ...

最新文章

  1. 用shell脚本配置oracle安装需求
  2. 大型银行数据中心用户安全管理
  3. [转] 为什么javascript是单线程的却能让AJAX异步调用?
  4. Chino的成绩(chino的公开赛T3)
  5. 【效率】推荐一款Markdown神器 ! ! !
  6. 在WebLogic 12c上运行RichFaces
  7. 华中科技大学期刊分类办法_紧跟国际前沿,拓展研究思路,立足国内实践,提升科研能力 —— 记国际期刊学术论文写作与发表研修班...
  8. CS217 1_Intro Hardware Accelerators for Machine Learning
  9. adventureworks mysql_AdventureWorks数据库的安装
  10. Linux 2038年问题
  11. RHEL7平台下电信拨号上网配置
  12. 对搜索引擎技术的认识和发展
  13. android模拟器 菜单键,夜神安卓模拟器系统设置有哪些?
  14. 《经济学通识》一、前言
  15. Python对电影Top250并进行数据分析
  16. 从零开始入门推荐算法工程师
  17. How to use Hibernate - XML Configuration
  18. 神经翻译笔记4扩展b. RNN的正则化方法
  19. 高斯与最小二乘法的故事
  20. 通常的六种网络拓扑结构

热门文章

  1. Cesium添加模型实时更新偏航角
  2. LaTex 中插入visio图片
  3. oracle客户端位数怎么看,【转】如何查看Oracle客户端版本及位数(Windows系统)...
  4. 《机器学习实战》:通俗理解支持向量机
  5. 【Python】Matplotlib局部放大图画法
  6. NAT模式下的虚拟机网络配置
  7. golang for循环详解
  8. 从最简单的源代码开始,切勿眼高手低---(第一波)
  9. android material design icon generator,傻瓜式 Material Design 风格矢量图标生成器
  10. insert操作获取自增主键的值