让我们从一个故事开始:当我的职业泡沫之外的人问我我在做什么时,我说“我建立网站”。如果他们好奇,我补充说这些网站相当复杂。如果他们继续问,我会尝试用一些例子来详细说明:Facebook、Spotify、Twitter。并不是我为这些公司工作,而是希望给他们一个“我建什么样的网站”的好印象。然而,大多数情况下,谈话不会超出“我建立网站”的范围,我对此没有意见。
如今,一个网站不等于另一个网站。网站的范围从产品营销网站到成熟的社交媒体平台。作为 web 开发的新手,要了解整个情况并不容易:从 HTML 和 CSS 的传统简单网站开始,从 web 服务器返回,变成一个复杂得多的具有复杂客户端的全栈应用程序- 服务器通信和状态管理。
如果您已经在学习 HTML、CSS 和 JavaScript,并且不了解网站和 Web 应用程序的基础知识,那么这本综合指南适合您。
在本演练中,我想向您展示 Web 开发从一个简单的网站到一个复杂的 Web 应用程序的演变过程,我们在其中澄清了以下术语:
- 客户端服务器
- 前端/后端
- 网站/网络应用程序
- 客户端应用程序/服务器应用程序
- 休息/图表QL
- 网络服务器/应用服务器
- 服务器端渲染 vs 客户端渲染
- 服务器端路由与客户端路由
- 单页应用程序与多页应用程序
- 代码拆分,延迟加载,tree shaking,......
- 全栈应用
- 静态网站生成
- BaaS、PaaS、IaaS、...
根据您当前作为 Web 开发人员的水平,我鼓励您在阅读本指南时随时休息一下,因为它非常广泛并且对于初学者来说可能有点不知所措,尤其是在最后。让我们开始吧 ...
目录
传统网站
如果您正在学习 Web 开发,您很可能会从使用 HTML 和 CSS 构建的传统网站开始。没有样式 (CSS) 且没有任何逻辑 (JavaScript) 的网站只是 HTML。
如果您在笔记本电脑或智能手机上的浏览器(例如 Firefox)中导航到特定URL,则会向负责该 URL 的 Web 服务器发出请求。如果网络服务器能够将请求与网站相匹配,那么它将为您的浏览器提供该网站的 HTML 文件。
为了将网站传输到浏览器,HTTP被用作客户端和 Web 服务器之间请求和响应的通信协议。这就是为什么每个 URL 前面都有“http”的原因。
客户端与服务器之间的通信是同步的,即客户端向服务器发送请求,并等待服务器的响应。您的网站不会立即显示,因为从客户端向 Web 服务器发送请求并从 Web 服务器接收响应需要时间。
HTTP 请求带有四种基本的 HTTP 方法:GET、POST、PUT 和 DELETE。HTTP GET 方法用于读取资源,而其余方法用于写入资源——其中资源可以是从 HTML 到 JSON 的任何内容。所有四种方法都可以抽象为臭名昭著的CRUD操作:创建、读取、更新和删除。
在我们的网站示例中,通过访问浏览器中的 URL 从 Web 服务器向客户端提供服务,浏览器执行 HTTP GET 方法以从 Web 服务器读取 HTML 文件。
客户端和服务器有什么区别?
客户端是使用服务器的实体。它要么从服务器读取资源,要么将资源写入服务器。对于传统网站,客户端就是您的浏览器。如果您在浏览器中导航到特定 URL,您的浏览器将与服务器通信以请求资源(例如 HTML)以显示网站。但是,客户端不必是浏览器(例如cURL)。
服务器是为客户端提供服务的实体。在传统意义上的网站中,服务器对客户端的请求做出反应,并使用来自 HTTP GET 请求的资源(例如 HTML、CSS、JavaScript)进行回复,或者确认来自 HTTP POST、PUT、DELETE 请求的操作。流行的 Web 服务器是一种特定类型的服务器,是NGINX或Apache。
可以说没有服务器就没有客户端,没有客户端就没有服务器。他们一起工作,即使他们不需要在同一个地方。例如,您机器上的浏览器位于您的本地位置(例如德国柏林),而为您提供网站服务的网络服务器则在远程位置运行(例如德国法兰克福)。服务器——也就是另一台计算机——通常位于本地机器之外的其他地方。为了开发 Web 应用程序或网站,您可能也在本地计算机上运行服务器(请参阅localhost)。
由于客户端不一定需要是本地计算机上的浏览器,因此它也可以位于远程位置。但稍后会详细介绍。
Web 服务器和应用程序服务器之间有什么区别?
Web服务器提供资源(例如 HTML、CSS 和 JavaScript),这些资源是可以通过 HTTP 传输的格式。当客户端向 Web 服务器请求资源时,Web 服务器通过将资源发送回客户端来完成请求。通常,这些资源只是服务器上的文件。如果将 HTML 发送到客户端,则客户端(在本例中为浏览器)解释 HTML 以呈现它。
相反,应用服务器提供 HTML、CSS 和 JavaScript 以外的资源。例如,如果客户端请求数据友好格式的数据,则可以发送JSON 。此外,应用程序服务器不受协议约束。Web 服务器主要使用 HTTP 协议,而应用程序服务器可以使用其他协议(例如用于实时通信的WebSockets )。最重要的事实是,应用程序服务器可以在其服务器端使用特定编程语言(例如JavaScript 和 Node.js、PHP、Java、Ruby、C#、Go、Rust 和 Python)实现细节。
Web 服务器和应用程序服务器都可以归类为服务器。因此,您经常会听到人们谈论服务器时指的是这两者之一。然而,人们通常所说的服务器是指一台物理计算机,它运行在远程某个地方,网络服务器或应用程序服务器正在运行。
您可能还会遇到另外两个术语:部署和托管。我将简要介绍这些术语:部署描述了在服务器上运行网站的行为,托管描述了从该服务器为网站提供服务的持续行为。所以,在自己的电脑上开发网站时,必须要用localhost URL打开,这就说明你是这个网站的本地主机。
当我更改 URL 的路径时会发生什么?
当我通过一个 URL 访问一个网站并围绕这个域(例如 mywebsite.com)从一个路径(例如 /about)导航到另一个路径(/home)时会发生什么?对于传统网站,客户端会针对每个不同的 URL 向 Web 服务器发出新请求。
对于每个 URL,一个不同的 HTTP GET 方法被发送到专用的 Web 服务器以完成请求。例如,当用户在浏览器中访问其/about
路径(也称为页面或路由http://www.mywebsite.com/about
)上的网站时,网络服务器会将有关此 URL 的所有信息发送回浏览器。这个过程称为服务器端路由,因为服务器决定在每个 URL 上将哪个资源发送给客户端。稍后您将了解客户端路由。
当我的网站不仅仅是 HTML 时会发生什么?
现代网站由 HTML(结构)、CSS(样式)和 JavaScript(逻辑)组成。没有 CSS,网站就不会闪亮,没有 JavaScript,网站就不会有动态交互。通常在使用 CSS 和 JavaScript 文件时,它们会链接在一个 HTML 文件中:
<link href="/media/examples/link-element-example.css" rel="stylesheet"> <h1>Home at /home route</p> <p class="danger">Red text as defined in the external CSS file.</p>
如果浏览器向 Web 服务器请求 URL 的 HTML,Web 服务器会发回 HTML 文件,其中可能包含链接到其他资源(如 CSS 或 JavaScript 文件)的 HTML 标记。对于每个链接,都会向 Web 服务器发出另一个请求以检索文件。
这些也称为瀑布请求,因为一个请求必须等待另一个请求完成。在我们的示例中,浏览器不知道它需要在带有 HTML 标记的 HTML 文件到达之前请求 CSS 文件link
。background
在下一个示例中,HTML 文件链接到 JavaScript 和 CSS 文件,而 CSS 文件链接到 JPG 文件(例如可以用作 CSS )。
然而,至少如果在一个文件中有多个引用,例如链接到 CSS 和 JavaScript 文件的初始 HTML 文件,这些资源将被并行请求和解析,如前一个示例所示,但也说明了下一个。
最终,浏览器将拥有特定 URL 的所有资源(例如 HTML、CSS、JavaScript、PNG、JPG、SVG),并解释 HTML 及其所有包含的资源以显示所需的结果。它已准备好让您作为用户与其进行交互。
WEB 2.0:从网站到 WEB 应用程序
最终,仅从 Web 服务器提供静态内容是不够的。在Web 2.0(2004 年左右)中,用户不仅可以阅读内容,还可以创建内容;这导致了动态内容。还记得之前的 HTTP 方法吗?到目前为止,我们只看到了读取资源的 HTTP GET 方法,但是其他 HTTP 方法呢?
随着 WordPress 等内容管理系统的兴起,Web 服务器必须让用户不仅可以查看资源,还可以操作它们。例如,使用内容管理系统的用户必须能够登录、创建博客文章、更新博客文章、删除博客文章以及注销。这时,PHP(可以由服务器端的网络服务器解释)编程语言最适合这类动态网站。
有了服务器端的逻辑,开发人员就可以处理来自用户的读写请求。如果用户想要创建博客文章(写操作),用户必须在浏览器中编写博客文章并单击“保存”按钮以将内容发送到运行在网络服务器上的服务器端逻辑。此逻辑验证用户是否已获得授权、验证博客内容并将内容写入数据库。所有这些权限都不允许发生在客户端上,否则任何人都可以在未经授权的情况下操作数据库。
由于我们仍然有服务器端路由,网络服务器能够在博文创建成功后将用户重定向到新页面。例如,重定向可能指向新发布的博客文章。如果没有重定向,HTTP POST/PUT/DELETE 请求通常会导致页面刷新/重新加载。
由于用户现在可以创建动态内容,我们需要有一个数据库来存储这些数据。数据库可以与 Web 服务器位于同一台物理服务器(计算机)上(最有可能出现在 Web 2.0 的早期),也可以位于另一台远程计算机上(最有可能出现在 Web 开发的现代时代)。
一旦将博客文章插入数据库,就可以为该博客文章生成一个唯一标识符,该标识符可用于将用户重定向到新发布的博客文章的 URL。所有这些仍然是异步发生的。
现在,在创建博客文章后,如果博客文章的数据不是静态的,而是存储在数据库中,服务器如何发送博客文章的 HTML 文件?这就是服务器端呈现的原理(不要误认为服务器端路由)发挥作用的地方。
具有面向消费者的网站(静态内容)的 Web 1.0 和具有面向生产者的网站(动态内容)的 Web 2.0 都从服务器返回 HTML。用户在浏览器中导航到一个 URL 并请求它的 HTML。但是,对于Web 2.0 中的动态内容,发送到客户端的HTML 不再是具有静态内容的静态HTML 文件。相反,它会使用服务器上数据库中的动态内容进行插值:
<?php if ($expression == true): ?> This will show if the expression is true. <?php else: ?> Otherwise this will show. <?php endif; ?>
用于不同编程语言的模板引擎(例如用于 Node.js 上的 JavaScript 的 Pug、用于 PHP 的 Twig、用于 Java 的 JSP、用于 Python 的 Django)允许在将 HTML 和动态数据发送到客户端之前对其进行插值。在服务器端呈现的帮助下,用户生成的内容可以通过在客户端请求时动态创建 HTML,以 HTML 的形式从服务器提供给客户端。
我们还在处理网站吗?从技术上讲是的,但是通过使用数据库从 Web 服务器(或应用程序服务器)提供动态内容来超越静态内容的网站也可以称为 Web 应用程序。不过,这两种类型之间的界限是模糊的。
Web 2.0 一词及其流行度在 2010 年左右减弱,因为 Web 2.0 的功能变得无处不在并失去了新鲜感。
单页应用程序
2010 年后单页应用程序 (SPA)的兴起使 JavaScript 流行起来。但我已经超前了。在这个时代之前,网站主要是用 HTML 加 CSS 和少量的 JavaScript 制作的。小 JavaScript 用于动画或 DOM 操作(例如删除、添加、修改 HTML 元素),但仅此而已。jQuery是执行此类任务的最流行的库之一。
但是谁会想到整个应用程序都可以用 JavaScript 构建呢?早期使用 JavaScript 编写单页应用程序的一些库/框架是 Knockout.js、Ember.js 和 Angular.js;而 React.js 和 Vue.js 是后来发布的。直到今天,它们中的大多数在现代 Web 应用程序中仍然非常活跃。
在单页应用程序出现之前,浏览器会从 Web 服务器请求网站的 HTML 文件和所有链接文件。如果用户碰巧在同一个域(例如 mywebsite.com)中从页面(例如 /home)导航到页面(例如 /about),则每次导航都会向 Web 服务器发出新的请求。
相比之下,单页应用程序主要将整个应用程序封装在 JavaScript 中,JavaScript 具有关于如何以及在其中使用 HTML(和 CSS)呈现的内容的所有知识。对于单页应用程序的最基本用法,浏览器只会请求一次 HTML 文件和一个域的一个链接 JavaScript 文件。
单页应用程序(此处为 React 应用程序)请求的 HTML 只是请求 JavaScript 应用程序(此处为bundle.js)的中间人,在客户端请求和解析后,将在 HTML 中呈现(这里id="app"
):
<!DOCTYPE html> <html> <head> <title>Hello HTML File which executes a React Application</title> </head> <body> <div id="app"></div> <script src="./bundle.js"></script> </body> </html>
从那里开始,React 从./bundle.js接管这个小 JavaScript :
import * as React from 'react'; import ReactDOM from 'react-dom'; const title = 'Hello React'; ReactDOM.render( <div>{title}</div>, document.getElementById('app') );
在这个小小的 React 应用程序中,只有一个名为的变量title
显示在 HTMLdiv
元素中。但是,HTMLdiv
元素之间的所有内容都可以替换为使用 React 组件及其模板语法 JSX 构建的整个 HTML 结构。
import * as React from 'react'; import ReactDOM from 'react-dom'; const App = () => { const [counter, setCounter] = React.useState(42); return ( <div> <button onClick={() => setCounter(counter + 1)}> Increase </button> <button onClick={() => setCounter(counter - 1)}> Decrease </button> {counter} </div> ); }; ReactDOM.render( <App />, document.getElementById('app') );
这本质上是早期的模板引擎,但只是在客户端而不是服务器上执行,因此这不再是服务器端渲染。
const App = () => { const [books, setBooks] = React.useState([ 'The Road to JavaScript', 'The Road to React', ]); const [text, setText] = React.useState(''); const handleAdd = () => { setBooks(books.concat(text)); setText(''); }; return ( <div> <input type="text" value={text} onChange={(event) => setText(event.target.value)} /> <button type="button" onClick={handleAdd} > Add </button> <List list={books} /> </div> ); }; const List = ({ list }) => ( <ul> {list.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> );
由于这种从服务器到客户端执行渲染的变化,我们现在将其称为客户端渲染。换句话说:我们不是直接从 Web 服务器提供预呈现的 HTML,而是主要从 Web 服务器提供 JavaScript,它在客户端执行,然后才呈现 HTML。通常术语 SPA 可以与术语客户端呈现的应用程序同义使用。
如果 SPA 仅从 Web 服务器请求一次,那么当用户在同一域内从一个页面导航到另一个页面(例如 mywebsite.com/about 到 mywebsite.com/home)而不请求另一个 HTML 时,它如何工作?
随着传统 SPA 的使用,我们也从服务器端路由转移到客户端路由。基本 SPA 最初请求的 JavaScript 文件封装了网站的所有页面。从一个页面(例如/about)导航到另一个页面(例如/home)不会对网络服务器执行任何请求。相反,客户端路由器(例如 React 的 React Router)接管以从最初请求的 JavaScript 文件中呈现适当的页面。
简而言之:基本的单页应用程序使用客户端呈现/路由而不是服务器端呈现/路由,同时仅从 Web 服务器检索整个应用程序一次。它是单个页面,因为整个应用程序只有一个请求,即链接到一个 JavaScript 文件的单个 HTML 页面;它封装了所有实际的 UI 页面并在客户端执行。
可以说,在我们拥有单页应用程序之前,我们一直在使用多页应用程序,因为对于每个页面(例如 /about),都会向 Web 服务器发出一个新请求,以检索所有必要的文件。然而,术语多页面应用程序并不是真正的东西,因为它是单页面应用程序流行之前的默认设置。
练习:
- 了解如何使用 React进行单页应用程序开发。
- 了解如何从头开始使用 Webpack 应用程序设置 React 。
代码拆分
我们了解到,默认情况下,SPA 以一个小的 HTML 文件和一个 JS 文件的形式发布。JavaScript 文件一开始很小,但随着应用程序变大,它的大小也会增加,因为更多 JavaScript 打包在一个bundle.js文件中。这会影响 SPA 的用户体验,因为将 JavaScript 文件从 Web 服务器传输到浏览器的初始加载时间最终会增加。加载所有文件后,用户可以从一个页面导航到另一个页面而不会中断(好)。但是,相比之下,初始加载时间会降低在浏览器中请求页面时的用户体验(不好)。
一旦应用程序的大小增长,将整个应用程序作为 JavaScript 文件请求将成为一个劣势。对于更复杂的单页应用程序,代码拆分(在 React + React Router 中也称为延迟加载)等技术用于仅服务当前页面所需的应用程序的一小部分(例如 mywebsite.com/home)。当导航到下一个页面(例如 mywebsite.com/about)时,将向 Web 服务器发出另一个请求以请求该页面的分数。
如果您回顾一下传统网站的工作方式,您会发现它与启用代码拆分的 SPA 非常相似。对于传统网站,每次用户导航到新路线时,都会加载一个新的 HTML 文件(带有可选的 CSS、JavaScript 和其他资产文件)。对于在路由级别进行代码拆分的 SPA,每次导航都会导致新请求的 JavaScript 文件。
我们仍然可以调用这个单页应用程序还是回到多页应用程序?你会看到术语最终是如何变得模糊的……
代码拆分不需要像前面的场景那样在路由级别发生。例如,人们也可以将更大的 React 组件提取到他们的独立 JavaScript 包中,这样它就只在实际使用它的页面上加载。
但是,如您所见,这会导致从 Web 服务器请求的冗余代码。当用户两次导航到代码拆分路由时也会发生同样的情况,因为它也会从 Web 服务器加载两次。因此,我们希望浏览器缓存(阅读:存储在用户机器上的浏览器缓存中)结果。
现在,如果捆绑的 table.js 文件发生更改,因为我们向表中引入了新功能,例如分页视图或树视图,会发生什么情况?如果启用缓存,我们仍会在浏览器中看到旧版本的 Table 组件。
作为此问题的解决方案,应用程序的每个新构建都会检查捆绑代码是否已更改。如果它发生了变化,它会收到一个新的文件名和一个基于时间戳的散列(例如table.hash123.js变成table.hash765.js )。当浏览器请求具有缓存文件名的文件时,它会使用缓存版本。但是,如果文件已更改并因此具有新的散列名称,则浏览器会请求新文件,因为兑现版本已过时。
另一个例子是第三方 JavaScript 库的代码拆分。例如,在为带有 Button 和 Dropdown 等组件的React 安装 UI 库时,也可以应用代码拆分。每个组件都是一个独立的 JavaScript 文件。从 UI 库导入 Button 组件时,只会导入 Button 中的 JavaScript,而不会导入 Dropdown 中的 JavaScript。
为了将 React 应用程序(或库)捆绑到一个或多个(带有代码拆分)JavaScript 文件,另一种称为tree shaking的技术开始发挥作用,它消除了死代码(阅读:未使用的代码),因此它不会打包在最终的包中. 从历史上看,JavaScript 中使用了以下打包器(从过去到最近):
练习:
- 了解如何在 React 中使用 React Router 进行客户端路由。
- 了解如何在路由级别使用代码拆分。
全栈应用
我们正在进入与 SPA 同时流行的全栈应用程序范例。全栈应用程序包括客户端(例如 SPA)和服务器应用程序。如果公司正在寻找全栈开发人员,他们通常希望有人能够在两端创建客户端-服务器应用程序。有时客户端和服务器共享相同的编程语言(例如客户端上的 JavaScript 和 React,服务器上的 JavaScript 和 Node.js),但它们不是必须的。
无论如何,为什么我们需要全栈应用程序?由于客户端单页应用程序的兴起,对全栈应用程序的需求诞生了。
到目前为止,我们从使用 HTML/CSS/JavaScript 的传统网站到现代 Web 应用程序(例如 React 应用程序)。渲染静态内容没问题,但如果只提供 JavaScript(和一点 HTML),我们如何渲染动态内容,例如像博客文章这样的用户特定内容(参见 Web 2.0,但这次是客户端渲染)在处理客户端呈现接管的 SPA 时,一个 Web 服务器到客户端?
SPA 应用程序(封装在 JavaScript 文件中)没有任何用户特定数据。这只是页面的逻辑;它们的外观以及它们在用户交互中的行为方式。实际数据并没有嵌入其中,因为它仍然位于数据库中的某个位置,并且不再在服务器上进行插值。这是从服务器端渲染转移到客户端渲染时必须做出的权衡。
因此,客户端需要再次向服务器(使用JavaScript/Node.js或其他编程语言编写的应用服务器)请求,以请求缺失的数据来填充客户端的空白。客户端模板引擎(例如React 中的 JSX)负责使用结构(HTML)插入内容(数据)。
在处理客户端呈现的应用程序时,基本上有两次请求往返:一次针对 JavaScript 应用程序,一次针对填充空白的数据。一旦一切都在浏览器中呈现,用户就开始与应用程序交互——例如通过创建新的博客文章。JSON 是从客户端向服务器发送数据的首选格式,反之亦然。服务器通过读取或写入数据库来处理来自客户端的所有请求;它可以在同一台物理服务器上,但不需要(例如,只是坐在另一台物理服务器上)。
客户端呈现的应用程序 (SPA) 附带一个警告,即从一开始就没有所有数据可供他们使用。他们必须要求一切以填补空白。作为网上冲浪的最终用户,您会以两种方式注意到客户端呈现的应用程序:
- 首先,有加载微调器(几乎无处不在),有时整个页面都有一个加载微调器,然后在一瞬间为较小的小部件加载多个微调器(瀑布请求),因为请求数据发生在呈现初始页面之后。
- 其次,从路由到路由的导航是即时的(不包括代码拆分,因为由于对服务器的额外捆绑请求,感觉有点慢)。这就是我们从 SPA 中获得的好处。
除了额外的数据获取往返之外,客户端呈现的应用程序还必须应对状态管理的挑战,因为用户交互和数据需要在客户端的某个地方存储和管理。
在使用 SPA 时考虑以下挑战:用户作为作者访问他们可以发布博客文章的网站。在当前页面,用户可以看到他们所有的博客文章,因此在加载此页面时需要获取所有这些博客文章。这些获取的博客文章在客户端的代码中保存为内存中的状态。现在,当用户开始与页面及其数据交互时,每篇博文都有一个按钮,允许用户单独删除每个条目。当用户点击删除按钮时会发生什么?让我们来看看这个场景:
用户单击删除按钮,该按钮向应用程序服务器发送一个请求,该请求以博客文章的标识符作为有效负载和删除它的指令(通常是 HTTP DELETE 就足够了)。在服务器上的所有权限检查(例如用户是否已授权,是否有博客文章,博客文章是否属于用户)完成后,服务器将操作委托给删除博客文章的数据库。数据库向服务器确认操作成功,然后服务器将响应发送回客户端。现在,客户端要么从内存中的本地状态中删除博客文章,要么再次从服务器获取所有博客文章,并用更新的博客文章列表替换内存中的博客文章。
在执行客户端路由时,可以通过状态管理最小化对数据(例如博客文章)的请求。这意味着理想情况下,用户从一个页面导航到另一个页面然后返回初始页面不应触发对初始页面所需数据的第二次请求。相反,它应该已经通过使用状态管理缓存在客户端上。
最后但并非最不重要的一点是,客户端和服务器之间的接口称为API。在这种情况下,它是两个远程实体(这里是客户端和服务器)之间的一种特定类型的 API,但是在编程中很多东西都称为 API。
练习:
- 详细了解不同类型的 API。
客户端-服务器通信
传统的全栈应用程序使用REST作为它们的 API 范式;它使用 HTTP 方法进行 CRUD 操作。以前,我们已经在文件和用户交互之间使用 HTTP 方法进行 CRUD 操作——没有遵循明确的限制——例如使用 PHP 等服务器端语言创建博客文章。
但是,在使用 REST API 时,我们是在RESTful 资源上使用这些 HTTP 方法。例如,RESTful 资源可以是博客文章。用户可以从应用服务器使用 HTTP GET 阅读博客文章,或者在应用服务器上使用 HTTP POST 创建新的博客文章。
REST API 连接客户端和服务器应用程序,而无需使用相同的编程语言来实现它们。他们只需要提供一个用于发送和接收 HTTP 请求和响应的库。REST 是一种不受数据格式(过去是 XML,但现在是 JSON)和编程语言的通信范式。
REST 的现代替代方案是用于客户端和服务器之间 API 的GraphQL。GraphQL 也未绑定到数据格式,与未绑定到 HTTP 的 REST 相比,但大多数情况下您会看到此处也使用 HTTP 和 JSON。
通过到目前为止讨论的技术,全栈应用程序将客户端和服务器应用程序分离。两者都通过精心挑选的 API(例如 REST 或 GraphQL)进行通信。当客户端应用程序在浏览器中呈现 Web 应用程序所需的一切时,服务器应用程序处理来自客户端的读写数据请求。
练习:
- 了解如何使用 Node.js 创建 REST API。
- 详细了解为什么要使用 GraphQL 而不是 REST。
- 了解如何将 GraphQL用于全栈 JavaScript 应用程序。
前端和后端
我们还没有讨论前端和后端这两个术语,因为我不想预先添加太多信息。前端应用程序可以是用户在浏览器中看到的所有内容(例如网站、Web 应用程序、SPA)。因此,您会看到前端开发人员最常使用 HTML/CSS 或类似 React.js 的库。相比之下,后端通常是幕后的逻辑:它是从数据库读取和写入数据库的逻辑,与其他应用程序对话的逻辑,通常是提供 API 的逻辑。
这两个实体都会导致客户端-服务器架构(前端和后端关系),而后端将需要用于 (A) 不应作为源代码公开给前端应用程序的业务逻辑(例如授权)——否则它将是可在浏览器中访问——或用于 (B) 建立与第三方数据源(例如数据库)的敏感连接。
但是,不要在这里将客户端应用程序始终误认为前端,而将服务器应用程序始终误认为后端。这些条款不能轻易交换。前端应用程序通常在浏览器中可见,而后端通常执行不应在浏览器中公开的业务逻辑,并且通常还连接到数据库。
但是,相比之下,客户端和服务器这两个术语是一个角度问题。使用另一个后端应用程序(后端 2)的后端应用程序(后端 1)成为服务器应用程序(后端 2)的客户端应用程序(后端 1)。但是,同一个后端应用程序(后端 1)仍然是另一个客户端应用程序的服务器,该客户端应用程序是前端应用程序(前端)。
如果有人问您实体在客户端-服务器体系结构中扮演什么角色,您想回答客户端-服务器问题,请始终问自己谁(服务器)为谁(客户端)服务以及谁(客户端)使用谁的(后端)功能?
微服务(可选)
例如,微服务是一种将一个大后端(也称为单体)拆分为多个较小后端(微服务)的架构。每个较小的后端可能具有一个特定领域的功能,但毕竟它们都服务于一个前端(或多个前端)。但是,一个后端也可以消费另一个后端,而前一个后端成为客户端,而后者成为服务器。
在微服务架构中,每个后端应用程序都可以使用不同的编程语言创建,而所有后端都能够通过 API 相互通信。他们选择哪种 API 范式并不重要,无论是 REST API 还是 GraphQL API,只要与他们的服务器对话的客户端了解 API 规范即可。也可能发生一个前端不只与一个后端对话,而是并排与多个后端对话的情况。
练习:
后端即服务(可选)
在传统意义上,一个单一的后端应用程序,它只为一个前端应用程序提供服务,通常会连接到一个数据库。这是一个典型的全栈应用程序。然而,大多数情况下,后端应用程序除了读取和写入数据库、允许某些用户执行某些操作(授权)或首先对用户进行身份验证(例如登录、注销、注册)之外,并没有做太多事情。地方。如果是这种情况,通常不需要自己实现后端应用程序。
Firebase(由 Google 提供)是后端即服务的一种解决方案,提供数据库、身份验证和授权作为开箱即用的后端。开发人员只剩下实现需要连接到此后端即服务的前端应用程序(例如 React 应用程序)。
诸如 Firebase 之类的后端即服务 (BaaS) 允许开发人员快速启动并运行其前端应用程序。从身份验证、授权和数据库的一切都为您完成。此外,大多数 BaaS 也提供托管服务,例如您的 React 应用程序也可以托管在 Firebase 上。因此,Firebase 将您的 React 应用程序提供给您的客户端(浏览器),并使您的应用程序能够与它对话以获取所有其他功能(例如身份验证、数据库)。一个流行的 Firebase 开源替代品是Supabase。
练习:
超越全栈应用
如果所有这些还不是让您感到困惑,请尝试了解全栈应用程序的最新发展。随着从传统网站到全栈应用程序的所有发展,您可能已经注意到从 X 到 Y 的转变常常使事情变得更加复杂......
- 服务器端路由 (X) 到客户端路由 (Y)
- 大包大小,可以通过代码拆分来解决
- 服务器端呈现 (X) 到客户端呈现 (Y)
- 额外(瀑布式)数据请求
- 为开发人员提供额外的数据获取和状态管理工作
- 最终用户的许多加载微调器
- 额外(瀑布式)数据请求
在下文中,我想向您介绍两种方法,它们的理念(SSR、SSG)并不新鲜,但在与现代库(例如 React)和元框架(例如 Next.js、Gatsby)一起使用时非常强大。 js) 使这些方法成为可能。我是一名 React 开发人员,这就是为什么对这些技术的建议是有偏见的,但是,我相信您也可以根据自己的喜好找到类似的技术。
服务器端渲染 2.0 (SSR)
我们之前了解过 Web 2.0 的服务器端渲染。在后来的某个时间点,全栈应用程序将客户端和服务器解耦,并引入了带有 React 等库的客户端渲染。那么再退一步,用 React 做服务端渲染呢?
当使用位于 React 之上的流行 Next.js 框架时,您仍在开发 React 应用程序。但是,您在 Next.js 中实现的所有内容都将在服务器端呈现 React。在 Next.js 中,您使用 React 实现每个页面(例如 /about、/home)。当用户从一个页面导航到另一个页面时,只有一小部分服务器端呈现的 React 被发送到浏览器。它的伟大之处在于:你已经可以请求数据来填充服务器上的空白,用 React 插入数据,然后将它无间隙地发送到客户端。
这与客户端渲染不同,因为 React 只接管客户端,并且只有在客户端最初渲染时没有数据时才开始请求数据来填补空白。使用 SSR React,您可以在服务器上插入 React 中的数据,但也可以选择在应用程序呈现时在客户端上获取数据。客户端渲染和服务器端渲染这两个选项可以混合使用。
- 优点:客户端收到已经填充了数据的 HTML(用户体验和搜索引擎优化的改进)。
- 缺点:客户端可能需要等待更长的时间,因为填充的 HTML 是在服务器上动态创建的(HTTP 缓存最大限度地减少了这个问题)。
练习:
- 了解我如何将 Next.js 用于我的课程网站。
- 学习用于 React 的Next.js。
静态站点生成 (SSG)
传统网站使用来自 Web 服务器的静态文件在浏览器上呈现。正如我们所了解的,没有应用服务器的参与,也没有服务器端渲染的参与。传统网站的方法非常简单,因为网络服务器只托管您的文件,用户访问浏览器的每个 URL 都会发出获取必要文件的请求。那么如果我们可以对静态文件使用 React 呢?
React 本身不适用于静态文件。相反,React 只是在客户端动态创建应用程序的 JavaScript 文件。但是,位于 React 之上的框架 Gatsby.js 用于为 React 应用程序生成静态站点。Gatsby 使用 React 应用程序并将其编译为静态 HTML 和 JavaScript 文件。然后所有这些文件都可以托管在网络服务器上。如果用户访问 URL,静态文件将提供给浏览器。
与服务器端渲染 React 相比,静态文件不是在用户请求时动态创建的,而是仅在构建时创建一次。对于数据经常变化的动态内容(例如电子商务)来说,这可能是一个缺点,但是,对于内容不经常变化的营销页面或博客,偶尔构建一次网站是完美的解决方案。
练习:
- 了解我如何将 Gatsby.js 用于我的网站。
- 学习用于 React 的Gatsby.js。
如果从网站到 Web 应用程序的这场马拉松比赛中有任何遗漏,请告诉我。我希望你喜欢阅读它!如果您认为向此博客文章添加更多内容并将其发布为 101 网络开发是个好主意,请告诉我并注册我的时事通讯以了解更多信息:-)
via https://www.robinwieruch.de/web-applications/