Express, 一個流行的 Node.js 框架
Express 是一個用於 Node.js 的 Web 框架。Node.js 是一個用於構建網絡服務和應用程序的神奇工具。Express 基於其功能提供了易於使用的功能,以滿足 Web 服務器用例的需求。
Express 簡介
Express 是一個 Node.js Web 框架。
Node.js 是一個用於構建網絡服務和應用程序的神奇工具。
Express 基於 Node.js 的功能提供了易於使用的功能,以滿足 Web 服務器用例的需求。Express 是開源、免費、易於擴展且非常高效的。還有很多預先建立的包可供使用,您只需放入並用於執行各種操作。
安裝
您可以使用 npm 將 Express 安裝到任何項目中:
1 | npm install express |
或者使用 Yarn 安裝:
1 | yarn add express |
這兩個命令在空目錄中也可以工作,當你從頭開始創建項目時(雖然 npm
不會創建 package.json
文件,而 Yarn 創建一個基本的 package.json
文件)。
如果您從頭開始創建一個新項目,只需運行 npm init
或 yarn init
。
Hello World
我們準備好創建我們的第一個 Express Web 服務器了。
這是一些代碼:
1 | const express = require('express') |
將此代碼保存到項目根目錄中的 index.js
文件中,然後使用以下命令啟動服務器
1 | node index.js |
您可以在本地打開瀏覽器,訪問 http://localhost:3000
,您應該會看到 Hello World!
消息。
通過理解 Hello World 代碼來學習 Express 的基本知識
以上的 4 行代碼在幕後完成了很多工作。
首先,我們將 express
包引入到 express
變量中。
通過調用 express()
方法,我們實例化了一個應用程序對象。
一旦我們有了應用程序對象,我們告訴它使用 get()
方法來聽取 /
路徑上的 GET 請求。
對於每個 HTTP 動詞,都有一個對應的方法: get()
,post()
,put()
,delete()
,patch()
:
1 | app.get('/', (req, res) => { /* */ }) |
這些方法接受一個回調函數 - 當請求開始時調用 - 我們需要對其進行處理。
我們傳入一個箭頭函數:
1 | (req, res) => res.send('Hello World!') |
Express 在這個回調函數中向我們發送兩個對象,我們稱之為 req
和 res
,它們分別代表請求和響應對象。
req
是 HTTP 請求。它提供了所有請求信息,包括請求參數、標頭、請求主體等等。
res
是 HTTP 響應對象,我們將向客戶端發送它。
在這個回調函數中我們做的是將 Hello World!
字符串發送給客戶端,使用 Response.send()
方法。
這個方法將該字符串設置為主體,並且關閉連接。
示例的最後一行實際上啟動了服務器,並告訴它在端口 3000
上監聽。我們傳入一個回調函數,當服務器準備好接受新請求時調用。
請求參數
我提到了請求對象保存了所有的 HTTP 請求信息。
這是您可能會使用的主要屬性:
屬性 | 描述 |
---|---|
.app | 保存對 Express 應用程序對象的引用 |
.baseUrl | 應用程序響應的基本路徑 |
.body | 包含提交的請求主體的數據(必須手動解析和填充才能訪問) |
.cookies | 包含請求中的 cookies(需要 cookie-parser 中間件) |
.hostname | Host HTTP 標頭 中定義的主機名 |
.ip | 客戶端 IP |
.method | 使用的 HTTP 方法 |
.params | 路由命名參數 |
.path | URL 路徑 |
.protocol | 請求的協議 |
.query | 一個包含請求中所有查詢字符串的對象 |
.secure | 如果請求是安全的(使用 HTTPS) 則為 true |
.signedCookies | 包含請求中的簽名 cookies(需要 cookie-parser 中間件) |
.xhr | 如果請求是 XMLHttpRequest,則為 true |
發送響應
在 Hello World 的示例中,我們使用了 Response.send()
方法來發送一個簡單的字符串作為響應,並關閉連接:
1 | (req, res) => res.send('Hello World!') |
如果您傳入一個字符串,它將將 Content-Type
標頭設置為 text/html
。
如果您傳入一個對象或數組,它將將 application/json
Content-Type
標頭設置並將該參數解析為 JSON。
send()
方法會自動設置 Content-Length
HTTP 響應標頭。
send()
也會自動關閉連接。
發送 JSON 響應
Response.json()
方法接受對象或數組,並在發送之前將其轉換為 JSON:
1 | res.json({ username: 'Flavio' }) |
使用 end() 發送空響應
在不包含主體的情況下發送響應的另一種方法是使用 Response.end()
方法:
1 | res.end() |
更改任何 HTTP 標頭值
您可以使用 Response.set()
更改任何 HTTP 標頭的值:
1 | res.set('Content-Type', 'text/html') |
Content-Type 標頭有一個快捷方式:
1 | res.type('.html') |
設置 cookie
使用 Response.cookie()
方法來操作 cookie。
示例:
1 | res.cookie('username', 'Flavio') |
這個方法接受一個包含各種選項的第三個參數:
1 | res.cookie('username', 'Flavio', { domain: '.flaviocopes.com', path: '/administrator', secure: true }) |
您可以設置的最有用的參數是:
值 | 描述 |
---|---|
domain |
cookie 域名 |
expires |
設置 cookie 失效日期。如果缺少或為 0,則該 cookie 是一個會話 cookie |
httpOnly |
將 cookie 設置為只能由 Web 服務器訪問。請參閱 HttpOnly |
maxAge |
相對於當前時間的過期時間,以毫秒為單位 |
path |
cookie 路徑。默認為 / |
secure |
將 cookie 設置為僅使用 HTTPS |
signed |
將 cookie 設置為已簽名 |
sameSite |
SameSite 的值 |
可以使用以下方法清除 cookie:
1 | res.clearCookie('username') |
設置 HTTP 響應狀態
使用 Response.status()
:
1 | res.status(404).end() |
或者
1 | res.status(404).send('File not found') |
sendStatus()
是一種快捷方式:
1 | res.sendStatus(200) |
處理重定向
重定向在 Web 開發中很常見。您可以使用 Response.redirect()
方法來創建重定向:
1 | res.redirect('/go-there') |
這創建了一個 302 重定向。
301 重定向可以這樣做:
1 | res.redirect(301, '/go-there') |
您可以指定絕對路徑(/go-there
)、絕對 URL (https://anothersite.com
)、相對路徑(go-there
),或者使用 ..
返回一級:
1 | res.redirect('../go-there') |
您還可以使用 Referer HTTP 標頭值(如果未設置,則默認為 /
) 將重定向返回到前一個 URL,使用以下方法:
1 | res.redirect('back') |
發送文件供下載
Response.download()
方法允許您發送一個附加到請求的文件。瀏覽器將保存該文件而不是顯示該頁面。
1 | res.download('/file.pdf') |
支持 JSONP
JSONP 是一種從客戶端 JavaScript 使用跨源 API 的方法。
您可以使用 Response.jsonp()
方法來支持 JSONP,這與 Response.json()
相似,但處理了 JSONP 調用:
1 | res.jsonp({ username: 'Flavio' }) |
路由
在 Hello World 的示例中,我們使用了以下代碼:
1 | app.get('/', (req, res) => { /* */ }) |
這創建了一個將根域名路徑 /
映射為我們要提供的響應的路由。
命名參數
如果我們想要聽取自定義請求怎麼辦?也許我們想要創建一個接受字符串並將其返回為大寫的服務。如果我們不希望將參數作為查詢字符串發送,而是作為 URL 的一部分,我們可以使用命名參數:
1 | app.get('/uppercase/:theValue', (req, res) => res.send(req.params.theValue.toUpperCase())) |
如果我們向 /uppercase/test
發送請求,我們將在響應的主體中得到 TEST
。
您可以在同一個 URL 中使用多個命名參數,它們都將存儲在 req.params
中。
使用正則表達式匹配路徑
您可以使用正則表達式來匹配多個路徑:
1 | app.get(/post/, (req, res) => { /* */ }) |
這將匹配 /post
、/post/first
、/thepost
、/posting/something
等等。
中間件
中間件是一個函數,它鉤入路由過程,在某些時候執行操作,具體取決於我們希望它做的事情。
通常用於編輯請求或響應對象,或者在它達到路由處理程序代碼之前終止請求。
用法如下:
1 | app.use((req, res, next) => { /* */ }) |
這與定義路由相似,但除了 Request 和 Response 對象實例之外,我們還將下一個中間件函數的引用,分配給變量 next
。
我們總是在我們的中間件函數的末尾調用 next()
,以將執行傳遞給下一個處理程序,除非我們想要提前結束響應並將其返回給客戶端。
通常情況下,您使用預製的中間件,以 npm
包的形式。可用的中間件列表可以在這裡找到: https://expressjs.com/en/resources/middleware.html。
一個例子是 cookie-parser
,它用於將 cookie 解析為 req.cookies
對象。您可以使用 npm install cookie-parser
安裝它,然後像這樣使用它:
1 | const express = require('express') |
您還可以為特定路由設置中間件函數,將其用作路由定義的第二個參數:
1 | const myMiddleware = (req, res, next) => { |
如果您需要將在中間件中生成的數據存儲以便將其傳遞給後續的中間件函數或請求處理程序,您可以使用 Request.locals
對象。它將數據附加到當前請求:
1 | req.locals.name = 'Flavio' |
提供靜態資源
通常在 public
子文件夾中有圖片、CSS 等文件,並將它們暴露到根級別:
1 | const express = require('express') |
如果在 public/
中有一個 index.html
文件,則將它提供給您現在訪問的根域名(http://localhost:3000
)
模板
Express 能夠處理服務器端模板。
Jade 是默認模板引擎,但您可以使用許多不同的模板引擎,包括 Pug、Mustache、EJS 等等。
假設我不喜歡 Jade(我確實不喜歡),想要改用 Handlebars。
您可以使用 npm install hbs
安裝它。
將 about.hbs
模板文件放在 views/
文件夾中:
然後使用以下 Express 配置在 /about
上提供它:
1 | const express = require('express') |
您還可以使用 express-react-views
套件 在服務器端渲染 React 應用程序。
首先使用 npm install express-react-views react react-dom
。
現在不使用 hbs
,而是使用 express-react-views
,並使用 jsx
文件作為引擎:
1 | const express = require('express') |
只需在 views/
中放一個 about.jsx
文件,訪問 /about
應該會顯示 “Hello from Flavio” 字符串:
1 | const React = require('react') |
下一步?
Express 在內部具有 Node.js 的所有強大功能。
您可以做任何您想要的事情,包括連接到數據庫、使用任何類型的緩存、Redis、使用 sockets,以及您可以在服務器上想像的任何操作。
只有天空是極限。