# Web的历史3️⃣-Web应用
<!--  truncate  -->

随着技术的不断发展，尤其是移动设备的普及和移动互联网的发展，使得动态网页对于日益复杂的需求力不从心。

具体地来说，业界开始需求Web的“应用化”，也就是要把网页变成一个应用程序：在以前，我们介绍的动态网页技术可以很好地支持博客，论坛，新闻网站，企业官网等；而现在，我们需要在浏览器上写文件(腾讯文档)，聊天(Discord),直播，点外卖,玩游戏(实际上，很多手机APP都是浏览器套壳，本质上就是向你展示一个网页；包括微信小程序，也是一个只可以使用微信内置浏览器打开的网站)

那些开发APP的程序员也很乐意把自己的项目搬到浏览器里，因为用HTML+CSS写GUI非常方便，而且Web😇具有跨平台的特性：你需要付出很多努力才能确保一个传统APP能在手机，电脑，MacOS,Windows,Linux上运行，但是你写网页只需要很轻松地写，不用考虑兼容，浏览器会确保你的网页在这些平台上都能运行。

包括我们的报修系统，也算是一个Web应用。Web应用相比传统的高级动态网页有如下特征：
- 页面少：动态网页可能要有成千上百个页面，所以必须使用模板动态生成。而应用程序可能只有几个或者几十个界面。
- 高交互：动态网页的主要目的是供人观看，用户的交互（例如点击链接，按钮等）比较少且简单。而Web应用中，用户的交互非常频繁且复杂。前后端通信更加频繁。
- 部分更新：动态网页在不同页面之间也有不变的内容，比如页头页脚之类的，但是这些内容只占网页的少部分；在应用程序中，页面的绝大部分元素都没有怎么变化，只有少部分数据会发生变化，这时候，每更新一次数据就请求一次新页面就十分浪费了。

Web应用程序的这些需求都是我们之前介绍的动态网页技术所不好满足的，于是Web开发进入了一个新时期：

## AJAX与前后端分离

### JavaScript
之前我们一直在介绍服务器的技术，而一直忽略了浏览器的发展。实际上，浏览器也慢慢变得复杂，也在慢慢进行技术演进。

在1995年，也就是差不多后端处于SSI和CGI的时代，网景公司的员工发明了一种编程语言，叫做"JavaScript",这是对当时新兴的Java Applet的回应。Java Applet可以让你在浏览器运行Java代码，和它同一生态位的一个技术大家应该很熟悉:Flash，不过它们后来都被淘汰了。

JavaScript作为Java Applet的竞争者，是专门设计出来在浏览器内运行的脚本语言。连名字都是在蹭Java的热度:)网景浏览器(也就是火狐浏览器的前身)为JavaScript提供了一个强大的能力：动态地改变当前页面HTML和CSS的内容。

另外，浏览器还为JavaScript提供了发起HTTP请求的接口，不只是GET请求。这本是非常强大的功能，不过，由于JavaScript早期语法混乱，再加上当时人们对于前端能力需求并不是太大，所以直到2010年左右，前端和JavaScript才被重视起来。也就是我们接下来的内容：

### AJAX
传统的动态网页有一个不灵活的特性：每次只能返回一个完整的页面。也就是说，要么不更新网页，要么就全部更新，没办法更新现有网页的一部分。

比如我们有一个在文章下面评论的功能：用户需要在文本框里输入评论，然后点击"发布评论"的按钮。如果创建成功，那么我们应该让用户看到"评论成功"的提示并且在评论区显示用户最新评论的内容；如果失败也要提示有关的信息。

传统的动态网页只能这么做：返回一个完整的网页，这个网页和用户之前的网页的大部分内容没有区别，只是多了提示的信息和新的评论。但实际上，页面的有效信息只有那一部分。这极大地浪费了网络带宽和服务器性能(因为要重新渲染)。

AJAX(Asynchronous JavaScript and XML)就是解决这一痛点的技术，既然JavaScript可以动态地修改页面内容，发送HTTP请求，那么就直接让JavaScript程序发送带有评论内容的POST请求到服务器，然后服务器返回纯数据(通常使用JSON或XML的格式，把数据用格式包装起来有一个术语，叫做"序列化")而不是HTML，送给JavaScript程序而不是浏览器，JavaScript根据返回的操作HTML或CSS，实现网页部分更新的效果。

AJAX的核心在于"异步"，浏览器发送请求后，不会等待后端返回数据，而是允许用户继续浏览。即是指在发评论时，页面不会整个刷新一下的特性。

### 一个AJAX报名系统的例子

下面举一个例子，来详细说明AJAX的工作原理：用户需要通过一个网页进行某项活动的报名，填写个人信息，然后点击网页上的提交按钮，服务端会返回报名的结果，成功还是失败，与传统的方法不同，服务器返回信息时不是重新返回一个HTML,而是让浏览器直接在原有的界面上（比如提交按钮的下面）显示报名的状态。

用户通过浏览器输入地址，使用`GET`方法发起对`http://example.org/submit`的请求，服务器程序获得请求后，在路由表中查得`/submit`这个路径匹配静态文件`/static/submit.html`，于是将文件发送给浏览器；

浏览器得到文件后开始解析渲染这个文件，发现这个html在头部又要求浏览器向服务器获取`submit.js`文件和`submit.css`文件，于是浏览器不需要用户处理自己又发送了两条`GET`的HTTP Request,在文件返回后，浏览器自动执行返回的脚本并应用CSS样式。脚本的内容是监听html文件中提交按钮的“点击”事件，当按钮被点击时，执行提交报名表函数。

返回的html文件包括了提示框，要求用户输入姓名，手机，空闲时间等信息，在这些输入栏的最下面有一个提交按钮，当点击这个按钮时，脚本中的指定函数就会被激活，这个函数将读取用户从上面输入进来的内容，做一些简单的认证（比如说手机号的格式等），如果检验失败则让用户重新填写信息。

如果检验成功，则将这些信息组织成一个JSON文件（虽然AJAX中的X就是XML，但是现在其实最常用JSON），向服务器发送一个`POST`请求，地址是`http://example.org/api/submit`,在请求体中包含刚才的JSON文件。

服务器在接收这个请求后，在路由模块中查得这个URL匹配`HandleTicket()`函数，于是这个请求的上下文全部转交给`HandleTicket()`这个函数，函数会创建一个`Ticket`类的实例，将数据做后端检验后赋给实例的成员，如果检验成功则调用方法`Ticket.Create()`录入数据库，并向客户端(在这里指JavaScript脚本，而不是用户)发送回应成功的状态码(200)；

检验的内容除了冗余检查格式是否合法之外，还要执行业务逻辑方面的检查：
- 一个人只准报名一次，所以如果数据库中存在“姓名”字段相同的记录的话，检验则不通过(这个只是个例子，所以不考虑重名的情况)
- 如果我们活动的时间的范围没有包含在空闲时间的范围内，检验则不通过，因为用户的时间和我们活动的时间冲突
- 如果数据库中的记录(表示报名成功的用户)大于或等于我们设定的数字的话，检验则不通过，因为人够了

如果检验没有成功，则回应失败的消息，除了依据失败的类型设置对应的错误码外，还要返回一个JSON文件来简述错误信息。

报名成功的消息的示例：

```JSON title="StatusCode:201 Created"



{
    "status":"success",
    "submit":{
        "name":"小明",
        "freeAt":"2023-11-25_15:00~19:00",
        "phone":12345678900
    },
    "createdAt":"2023-11-23_9:23:22"
    "message":"恭喜！你已成功报名我们的活动"
}

```

报名失败的消息的示例：

```JSON title="StatusCode:400 Bad Request"

{
    "status":"fail",
    "submit":{
        "name":"小明",
        "freeAt":"2023-11-25_9:00~15:00",
        "phone":12345678900
    },
    "createdAt":"2023-11-23_9:23:22"
    "message":"抱歉，你的空闲时间与我们的活动时间有冲突"
}

```



在JavaScript脚本接收到回应后，根据返回的内容，操作html文件的内容，在提交按钮的下面一行插入一个文本块：

报名成功时：

```HTML

<div class="json_responses">
    <p class="json:message">恭喜！你已成功报名我们的活动</p>
    <p>请检查你的信息：</p>
    <p class="json:submit.name">姓名：小明</p>
    <p class="json:submit.freeAt">空闲时间：2023-11-25 15:00至19:00</p>
    <p class="json:submit.phone">手机号：12345678900</p>
    <p class="json:createdAt">服务端提交创建时间：2023-11-23 9:23:22</p>
</div>

```

报名失败时：

```HTML

<div class="json_responses">
    <p class="json:message">报名失败！抱歉，你的空闲时间与我们的活动时间有冲突</p>
    <p>请检查你的信息：</p>
    <p class="json:submit.name">姓名：小明</p>
    <p class="json:submit.freeAt">空闲时间：2023-11-25 9:00至15:00</p>
    <p class="json:submit.phone">手机号：12345678900</p>
    <p class="json:createdAt">服务端提交创建时间：2023-11-23 9:23:22</p>
</div>

```

使用AJAX技术，用户会发现，在写完信息点击提交按钮后，页面没有变化，过了1秒，按钮下面出现了提示信息。这给用户的体验非常像传统的桌面APP。

如果不使用AJAX技术，那么用户会发现在按下按钮后，网页会白屏刷新一段时间，过了几秒，返回了一个新页面，提示了报名状态信息。这样的应用虽然不是不能用，但是用户体验总是不如AJAX来的无缝，自然。性能也不好。

### API驱动与前后端分离
在上面那个例子里，服务器并没有返回HTML，而是返回纯数据，交给前端渲染。既然浏览器自己就能根据数据渲染HTML，那么后端也就没必要返回成品HTML了。

可以发现，这实际上就是把MVC架构中的"Views"部分推给了前端，后端只需要通过HTTP传递数据给前端JavaScript,前端JavaScript再渲染成HTML。后端返回纯数据，由前端渲染的模式称之为**前后端分离**；

而这样返回数据的URL也不能称之为"网页"了，因为它从给人看变成了给JavaScript程序看，这样的URL实际上变成了前端程序和后端程序这两个程序之间交互的接口，所以这种URL我们称之为**HTTP API**，一个主要是API而不是HTML网页的网站，我们称之为"API驱动"的网站。


#### REST API

不知道你还记得前面说的“虚拟路由”吗？这被广泛地运用在如今的API设计下，比如说我要获取某篇文章下面的全部评论，评论获取API可能是这样的：`GET http://example.org/api/getComments?article_id=123123`。

这种设计模式把一个URL看作一个业务窗口，窗口的作用是办理一个业务，在这个例子里`getComments`办理的业务就是“获取评论区”，非常的直观。

这种面向业务的API设计对于小规模项目非常方便，如果你的API接口只有几十个的话那使用这种设计也无妨，不过如果你的业务多起来的的话，这种设计是非常难以管理的。

现代的API设计采用面向资源的设计模式，把一个URL看作一个资源，例如我们重写上面的获取评论API:`GET http://example.org/article/123123/comments`

文章的评论是一项资源，一个URL就是获取这个资源，文章本身也是一项资源，如果我们要查看文章内容的话，我们可以这样写：`GET http://example.org/article/123123`,如果我们要上传评论的话，可以写`POST http://example.org/article/123123/comments`，在请求体里面带上评论。获取和上传评论，URL是一样的，只是方法不一样，这就利用了HTTP方法：例如，要删除评论区下的第15条评论的话，可以这样写：`DELETE http://example.org/article/123123/comments/15`



如果我们要获取评论区下某个用户发过的其他评论的话，我们可以这么写:`GET http://example.org/user/456456/comments`，核心思想是，一个URL是一个资源，方法是对资源的操作。

你看，这有点像传统的文件系统路由，但是这是完全在后端程序里实现的虚拟的“文件资源系统”，在URL后对应的并不是文件，而是和数据库打交道的Model板块函数。这种方式，就是所谓的REST，以这种方式设计的API,就叫REST API。

GitHub的API设计可以说是REST风格的典范，你可以抽空看看。





## 单页应用(SPA)
API驱动架构发展到极致就是所谓的"单页应用"，顾名思义，服务器只会在用户打开网页时加载一段html文件和一些JavaScript脚本(也就是一个页面)，后面的全部内容都是通过JavaScript动态更新的。JavaScript和服务器的后端接口交互主要就是采用AJAX。现代网站，或者说Web应用，通常流行这种单页应用架构。

单页应用的坏处就是打破了为静态网页文件设计的“收藏”功能和前进后退，也不利于SEO和无障碍，因为用户在网站上只打开一个网页，网页的内容根据用户操作由浏览器脚本动态更新，而生成的html也大多没有做语义化优化，难以被理解和解析。当然这些问题有解决方案，下面会讲到。

SPA的例子就是邮箱应用（比如Gmail）,通过浏览器访问你的邮箱，通过邮箱的主页面点某个邮件，你并没有进入一个新的页面，而是在原有的页面上，内容变成了邮件查看的界面，如果在主页面上点击发件的话，同样也没有一个发件页面，而是直接呈现发件的UI。

### 框架
作为"应用"，SPA是很复杂的，我们开发桌面应用也不是从底层一路造轮子，而是用Qt,GTK这种框架，同样Web应用也有框架，其中最主要的两个就是`Vue.js`和`React.js`，这些框架提供了Web应用需要的种种功能，我们介绍其中主要的几个方面：

### UI组件
SPA框架通常把整个页面的UI分成许多的"组件"，当页面变得复杂时，手动管理DOM会变得非常繁琐且容易出错。组件则抽象了复杂的DOM，使其变成有组织，易维护，可复用的一个个单元。

更重要的是，主流框架提供了"声明式UI编程"的方法，这使得你像是在写UI的配置文件，而不是操纵这些UI的程序；你告诉框架"做什么"，而不是"怎么做"，框架会自动解析你的声明，随着数据的变化自动更新UI组件，你要做的就是告诉框架在某种数据状态下哪个组件需要是怎么样的。用行话讲这叫做"数据驱动视图"。

这样，就可以让开发者可以像搭积木一样构建用户界面，并且当数据变化时，框架会自动更新界面，极大地提高了开发效率。

### 虚拟DOM

尽管JavaScript可以动态修改DOM，但频繁地直接操作真实DOM是非常耗费性能的。每次DOM操作都需要浏览器重新渲染一遍全部内容。在复杂或数据频繁变化的界面中，这会导致页面卡顿，用户体验下降。

为了解决这个问题，许多SPA框架引入了虚拟DOM的概念。虚拟DOM是一个缓冲区：当数据发生变化时，框架不会直接修改真实DOM，而是先在内存中构建一个新的虚拟DOM树，等到积累到一定的改动，再一次性应用全部的DOM操作。

这种机制的目的是将真实的DOM操作次数降到最低。这显著优化了渲染性能，尤其是在数据频繁变化的复杂界面中，虚拟DOM能够提供更好的性能。另外虚拟DOM也有利于管理状态，增加清晰度：



### 状态管理
基于Web前端技术栈的单页应用和传统桌面应用程序有一个很大的不同：渲染Web应用界面所基于的数据有着异步获取，分散来源的特点。在流行的REST风格的API设计下，服务器不负责记录状态，所以整理数据，维持状态的重任就全部交由前端负责。

偏偏前端技术栈又不是为开发这种复杂应用而诞生的：HTML最初就是一个标记格式的简单机制，JavaScript最初被用来写简单的脚本，为了保持兼容性，现代框架必须在这种基础上开发，而不是重构。

作为前端开发核心的DOM对象，其本身就是一个巨大的全局状态，所以前端开发天生没有选择像传统桌面开发那样把状态放在各个对象中进行操作，而是维护一个全局的状态，任何操作都是对这个全局的对象进行操作。

这种不良的设计风格，加上RESTful API和HTTP协议的无状态特性,导致前端技术栈天生不适合开发复杂的应用程序：当应用逻辑变得复杂时，通过直接操作DOM来更新视图，就极易导致代码混乱，状态难以追踪，很容易把代码写成一坨浆糊。

正如前面提到的，我们又不能重构浏览器的底层技术栈，所以必须在这一屎山上构建我们的项目。由于在SPA下不再刷新页面，前端需要自己维护一个与UI保持同步的数据状态。这就要考虑如何解耦模块和数据一致性的问题了。

这本来可以通过OOP+设计模式解决，不过我们说过，DOM的存在使得程序员要迎合这一模式，将状态以全局的方式保存，由异步数据来异步操作DOM也容易引起数据竞争。这就极大限制了OOP的发挥，那还有什么办法呢？

于是函数式编程(FP)这个学院派的范式就进入了前端程序员的视野。FP对于前端的这一痛点提供了极佳的解决方案。现在我们不修改原状态，而是创建一个新的状态替代原状态(不可变数据)；我们的函数，现在除了输出数据外不进行任何类似于`console.log()`的其它操作(纯函数)。等等诸如此类的编程思想基本上成为了现代前端开发的基石。使得SPA更容易规范开发和调试。

手写FP框架自然不太好，本着不重复造轮子的精神，前端提供了许多践行着FP范式的状态管理库，帮助前端程序员进行复杂程序的状态管理；Vue和React的状态管理框架分别叫Vuex/Pinia(在Vue3)和Redux。状态管理是现代Web应用前端开发的重要部分。
:::info

这个部分的内容可能有点难以理解，不过理解这一部分对于成为一个优秀的前端程序员是非常重要的。你也可以在这之后了解关于FP范式的主要思想，这对开发现代和优秀的程序是很重要的，因为FP是编程界的下一个技术潮流，比如Rust，其设计就大量参考了FP思想，甚至Rust早期就是用OCaml开发的😃

:::

### 前端路由和首屏优化
前面提到SPA打破了浏览器UX和搜索引擎对网站的检测，这些框架提供了API来改变地址栏中的内容，对于不同的页面可以设置不同的URL，来使得逻辑更加清晰，收藏栏也可以正常地使用了。

SPA因为需要初始化大量JavaScript程序，对于网络连接或者设备性能不好的用户，他们会看到长时间的白屏，首屏优化就是在一开始的html中加入一些信息，比如给用户看一个`加载中...`的动画，让用户耐心等待。或者是在`head`栏里放一些信息，使得网站可以被搜索引擎更好地搜到。

### 构建系统
浏览器其实并不能直接理解前端框架(Vue,React等)写的代码。因为它们并不是标准JavaScript，它们含有大量自定义的语法。因此，前端开发必须要把使用了框架的代码**编译**成浏览器可以理解的HTML,CSS,JavaScript。请注意，类似JQuery这样的库是不需要编译的，因为它们并没有超出原生的JavaScript功能和语法，而只是一个类库。你只需要在你的HTML里包含它们就可以。

构建系统是现代前端开发的重要一环，除了编译高级JavaScript代码外，构建系统通常还会做一些打包，压缩等杂活；这是现代前端开发必不可少的一环。常用的构建系统有Vite和Webpack

---

JavaScript并不是天生开发复杂应用的语言，所以SPA框架提供了那么多的机制，来把这个为简单脚本设计的语言变成一个足够开发可靠Web应用的语言，尽管一层一层的嵌套拖慢了性能，但是Web的性能瓶颈通常不在于计算而是I/O,加上业界大环境的各种因素,导致了前端基本几天就要推出新技术，眼花缭乱层出不穷，但是这些技术底层都是差不多的。重要的是不要被各种宣传迷惑了认知，而要认清它们的本质。

![JavaScript fatigue](/img/blog/comic.png)
> "JavaScript Fatigue"，图源[Auth0博客](https://auth0.com/blog/how-to-manage-javascript-fatigue/)

## JavaScript全栈
### Node.js
前面提到，JavaScript是专门设计运行在浏览器中的语言，也就是说，JavaScript的运行时就是浏览器，不过JavaScript也有浏览器之外的运行时，最出名的叫做`Node.js`；

简单来说，Node.js 让JavaScript走出了浏览器，可以直接在服务器上运行了。这意味着，开发者可以用同一种语言（JavaScript）来编写前端（用户在浏览器里看到的界面）和后端（服务器上处理数据的逻辑），这就是所谓的‘JavaScript全栈’开发。常见的JavaScript后端框架有Express.js Koa.js Nest.js。
### Web开发之外
Node.js能做的也不只是Web开发，传统编程语言可以做的Node.js都可以，在Web外最重要的领域就是桌面开发了，通常使用Electron框架，可以让你使用HTML,CSS来编写GUI界面，用JavaScript来操作界面。

因为依赖问题，通常每个Electron App 都打包了自己的Node.js运行时，每安装一个App，就相当于安装了一个浏览器内核。这严重浪费了电脑的内存和硬盘空间，但好处就是方便了开发。会写Web就能做桌面开发，降低了学习成本，也更方便跨平台。

## 最新技术
### WebSocket
HTTP已经很好了，但是协议本身有一个缺点:一个HTTP连接分为请求和响应，只能由客户端发起请求，服务端返回响应，如果客户端没有先发一点什么给服务端的话，服务端是没办法先给客户端发信息的，这就给一些更加复杂的要求增添了障碍：比如通过浏览器和别人聊天，需要接受来自服务器发给你的其他人的聊天的信息；或者是在浏览器上玩游戏，需要和服务器交换数据。这可以通过轮询来解决，但是这样还是不方便，效率也较低。

WebSocket是一个全新的协议，支持客户端和服务器的全双工通信，即客户端和服务器都可以主动地发消息，而且可以同时进行，而且是采用较小的数据帧格式，降低了网络开销，提高了数据传输速度。WebSocket在建立连接后保持长时间有效，不需要为每次消息发送重新建立连接，因此效率更高。

为了兼容HTTP协议，WebSocket也是监听80和443端口(HTTPS),握手采用了HTTP协议，通过升级协议来建立连接，如果可以升级，服务器会返回101状态码，升级连接.


### WebAssembly
WebAssembly是最近新出现的技术，他允许开发者将C/C++ , Rust等原本的一些编译型语言编译成浏览器可以执行的字节码，使得在浏览器中也可以执行这些程序，目前也有一些使用WebAssembly的应用，可以去看看，最大的好处就是不会JavaScript也能开发前端，也可以复用以前为桌面写的代码。这还是一个非常新兴的领域，值得技术投资😄

## 总结与资源
Web的历史总共经历了三个阶段：首先为了传输基本文件而发明了HTTP，为了方便地预览文档而发明了HTML和CSS，这是Web的静态网页的时代；为了给静态网页增加动态内容，批量生成许多的网页，人们发明了动态网页技术，形成了后端程序的概念，这是动态网页的时代；为了让客户端浏览器更加强大，给后端减负，人们发明了JavaScript，又搭建了复杂的Web应用程序，形成了前端程序的概念，这是Web的应用程序时代。

虽然技术变得越来越复杂，但是发展的脉络是可以抓住的：Web由于其特性，被人们承载了越来越高的期望：从操作文件，到浏览信息，到成熟的应用程序平台。最重要的是知道Web的诸多名词，概念，技术并不是突然出现的，而是经历了半个世纪的历史沉淀，它们也不是为了创新而创新，每个技术能够出现并受到欢迎，一定是因为解决了某个痛点才有了价值。

### 编年史
按照时间顺序总结对Web意义重大的技术：

<details>
<summary>编年史(AI写的，可能有点小错误)</summary>
<h3 id="-1966-1990-">早期 (1966-1990)</h3><ul><li><p>1966年</p><p>  互联网的前身“阿帕网” (ARPANET) 立项: 美国国防部高级研究计划局（ARPA）启动了阿帕网项目，旨在研究能够在部分网络遭到破坏后仍能维持通信的计算机网络。</p></li><li><p>1969年</p><p>  阿帕网首次成功通信: 10月29日，阿帕网上的第一条消息成功从加州大学洛杉矶分校（UCLA）发送到斯坦福研究院（SRI）。</p></li><li><p>1983年</p><p>  TCP/IP协议成为阿帕网标准: 1月1日，TCP/IP协议取代了原有的网络控制协议（NCP），成为阿帕网的标准通信协议，这一事件被认为是互联网诞生的标志。</p></li><li><p>1989年</p><p>  HTTP协议被发明: Tim Berners-Lee在欧洲核子研究中心（CERN）发明了超文本传输协议（HTTP），为万维网的诞生奠定了基础。</p></li><li><p>1990年</p><p>  HTML被发明: Tim Berners-Lee开发了超文本标记语言（HTML），作为创建网页的标准化语言。</p><p>  世界上第一个网页浏览器和Web服务器诞生: Tim Berners-Lee编写了第一个网页浏览器WorldWideWeb（后改名为Nexus）和第一个Web服务器CERN httpd。</p></li></ul><h3 id="-1991-2004-">萌芽与成长 (1991-2004)</h3><ul><li><p>1991年</p><p>  互联网向公众开放: 8月6日，Tim Berners-Lee在公共新闻组上发布了万维网项目，标志着互联网开始向公众开放，并逐渐普及。</p></li><li><p>1993年</p><p>  NCSA Mosaic浏览器发布: NCSA（美国国家超级计算应用中心）发布了Mosaic浏览器，这是第一个能够图文混排的浏览器，极大地推动了Web的普及。</p><p>  CGI被发明: NCSA HTTPd服务器第一个实现了通用网关接口（CGI），使得Web服务器能够调用外部程序，从而实现动态网页。</p></li><li><p>1994年</p><p>  HTTPS协议被发明: Netscape公司发明了HTTPS协议（安全的HTTP），并在其浏览器中实现。</p><p>  Netscape浏览器发布: Netscape Navigator发布，迅速成为当时最流行的浏览器。</p><p>  CSS被发明: Håkon Wium Lie首次提出了层叠样式表（CSS）的构想。</p></li><li><p>1995年</p><p>  MySQL首次发布: MySQL数据库的第一个内部版本发布，之后逐渐发展成为Web领域最受欢迎的开源数据库之一。</p><p>  Apache项目启动: Apache项目组接手了NCSA HTTPd的开发，并将其发展成为至今仍然非常流行的Apache HTTP Server。</p><p>  JavaScript发布: Netscape公司发布了JavaScript（最初名为LiveScript），为网页添加了动态交互能力。</p><p>  PHP发布: Rasmus Lerdorf发布了PHP（Personal Home Page Tools），一种用于创建动态网页的服务器端脚本语言。</p></li><li><p>1996年</p><p>  HTTP/1.0发布: HTTP/1.0作为RFC 1945发布，对早期的HTTP协议进行了补充和规范。</p><p>  CSS 1成为W3C推荐标准：CSS Level 1正式发布，为网页样式提供了标准化方案。</p><p>  XML被发明: W3C开始制定可扩展标记语言（XML），旨在以结构化的方式传输和存储数据。</p></li><li><p>1997年</p><p>  HTTP/1.1发布: HTTP/1.1作为RFC 2068发布，引入了持久连接、管道化和分块传输等重要改进，至今仍是广泛使用的协议版本。</p><p>  Java Servlet发布: Sun Microsystems发布了Java Servlet技术，提供了一种在Web服务器上运行Java程序的方式。</p></li><li><p>1998年</p><p>  XMLHttpRequest对象出现: 微软在Internet Explorer 5.0中首次引入了XMLHttpRequest对象，为日后AJAX的出现奠定了基础。</p></li><li><p>1999年</p><p>  JSP发布: Sun Microsystems发布了JavaServer Pages（JSP），允许开发者将Java代码嵌入到HTML页面中。</p><p>  HTML 4.01发布: HTML 4.01成为W3C推荐标准，是2000年代使用最广泛的HTML版本。</p></li><li><p>2000年</p><p>  REST被提出: Roy Fielding在他的博士论文中提出了表述性状态转移（REST）的软件架构风格，为Web API的设计提供了重要的理论指导。</p><p>  JSON被发明: Douglas Crockford提出了JavaScript对象表示法（JSON），作为一种轻量级的数据交换格式。</p></li><li><p>2002年</p><p>  Firefox发布: Mozilla基金会发布了Firefox浏览器，作为Netscape的继任者，以其开源、可扩展和对Web标准的良好支持而受到欢迎。</p></li><li><p>2004年</p><p>  Ruby On Rails发布: David Heinemeier Hansson发布了Ruby on Rails，这是一个全栈Web应用框架，以其“约定大于配置”的理念和快速开发能力而闻名。</p></li></ul><h3 id="-2005-">繁荣与变革 (2005至今)</h3><ul><li><p>2005年</p><p>  MVC架构的流行: 模型-视图-控制器（MVC）架构模式大约在2000年代中期随着Ruby on Rails和Django等框架的兴起而在Web开发领域流行起来。</p><p>  AJAX被广泛认知: Jesse James Garrett创造了AJAX（Asynchronous JavaScript and XML）这个术语，描述了一种使用现有技术创建更具动态性和交互性的Web应用的方法。</p><p>  Django发布: Django，一个基于Python的高级Web框架，首次发布。</p></li><li><p>2006年</p><p>  jQuery发布: John Resig发布了jQuery，这是一个快速、小巧且功能丰富的JavaScript库，极大地简化了HTML文档遍历、事件处理、动画和Ajax交互。</p></li><li><p>2008年</p><p>  HTML5第一份公开草案发布: WHATWG发布了HTML5的第一份公开工作草案。</p></li><li><p>2009年</p><p>  Node.js发布: Ryan Dahl发布了Node.js，这是一个基于Chrome V8引擎的JavaScript运行环境，使得JavaScript可以在服务器端运行。</p><p>  ES5发布: ECMAScript 5（ES5）发布，为JavaScript语言带来了重要的改进，例如严格模式和对JSON的原生支持。</p><p>  AngularJS发布: Google发布了AngularJS，这是第一个被广泛采用的现代前端框架，引入了数据绑定、依赖注入等概念。</p></li><li><p>2010年</p><p>  Express.js发布: Express.js，一个基于Node.js平台的极简、灵活的web应用开发框架，首次发布。</p></li><li><p>2011年</p><p>  WebSocket协议标准化: WebSocket协议被IETF标准化为RFC 6455，提供了浏览器与服务器之间全双工通信的能力。</p></li><li><p>2013年</p><p>  前后端分离架构的兴起: 大约在2013年左右，随着前端框架（如AngularJS, React）的成熟和RESTful API的普及，前后端分离的架构模式开始兴起。</p><p>  React.js发布: Facebook发布了React.js，这是一个用于构建用户界面的JavaScript库，以其组件化和虚拟DOM的概念而受到欢迎。</p><p>  Electron发布: GitHub发布了Electron（最初名为Atom Shell），这是一个使用Web技术构建跨平台桌面应用的框架。</p></li><li><p>2014年</p><p>  HTML5正式发布: W3C正式发布了HTML5推荐标准。</p><p>  Vue.js发布: 尤雨溪发布了Vue.js，这是一个渐进式JavaScript框架，以其易用性和灵活性而著称。</p><p>  SPA架构的流行: 单页面应用（SPA）架构随着AJAX的出现和前端框架的发展而逐渐流行，大约在2010年代中期成为构建富交互Web应用的主流方式。</p></li><li><p>2015年</p><p>  ES6发布: ECMAScript 2015（ES6）发布，为JavaScript带来了大量新特性，如类、模块、箭头函数、Promise等，是JavaScript语言的一次重大更新。</p><p>  REST开始流行: 随着移动互联网和前后端分离架构的兴起，RESTful API成为Web服务的主流设计风格。</p><p>  WebAssembly首次宣布: WebAssembly，一种新的、可移植的、大小和加载时间高效的格式，旨在为Web带来近乎原生的性能，首次被宣布。</p></li><li><p>2016年</p><p>  Next.js发布: Vercel（当时名为ZEIT）发布了Next.js，这是一个基于React的服务端渲染框架，简化了React应用的开发。</p></li></ul><ul><li><p>2017年</p><p>  WebAssembly MVP发布: WebAssembly的最小可行产品（MVP）在主流浏览器中得到支持。</p></li><li><p>2018年</p><p>  WebAssembly首个公开工作草案发布: W3C发布了WebAssembly核心规范、JavaScript接口和Web API的第一个公开工作草案。</p></li><li><p>2019年</p><p>  WebAssembly成为W3C推荐标准: WebAssembly核心规范成为W3C的官方推荐标准。</p></li></ul>
</details>

### 资源
*(MDN是一个非常好的网站，是开发FireFox的Mozilla公司写的，基本上是前端开发的圣经了，对于后端人，这个网站也有许多很好的内容)*
1. [关于HTTP协议的详细解释](https://developer.mozilla.org/zh-CN/docs/Web/HTTP)
2. [Web开发教程](https://developer.mozilla.org/zh-CN/docs/Learn_web_development) *HTML,CSS,JavaScript都有，需要学什么就去看什么*
3. [后端开发教程](https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Extensions/Server-side)

:::info

这是三篇系列文章中的第**3**篇

点击以跳转：

[HTTP](/blog/Web的历史1️⃣-HTTP)

[动态网页](/blog/Web的历史2️⃣-动态网页)

**Web应用**(你在看的文章)

:::

