日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【详细教程】教你如何使用Node + Express + Typescript开发一个应用

發布時間:2023/12/2 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【详细教程】教你如何使用Node + Express + Typescript开发一个应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Express是nodejs開發中普遍使用的一個框架,下面要談的是如何結合Typescript去使用。

目標

我們的目標是能夠使用Typescript快速開發我們的應用程序,而最終我們的應用程序卻是編譯為原始的JavaScript代碼,以由nodejs運行時來執行。

初始化設置

首要的是我們要創建一個目錄名為express-typescript-app來存放我們的項目代碼:

mkdir?express-typescript-app cd?express-typescript-app

為了實現我們的目標,首先我們需要區分哪些是線上程序依賴項,哪些是開發依賴項,這樣可以確保最終編譯的代碼都是有用的。

在這個教程中,將使用yarn命令作為程序包管理器,當然npm也是一樣可以的。

生產環境依賴

express作為程序的主體框架,在生產環境中是必不可少的,需要安裝

yarn?add?express

這樣當前目錄下就生成了一個package.json 文件,里面暫時只有一個依賴

開發環境依賴項

在開發環境中我們將要使用Typescript編寫代碼。所以我們需要安裝typescript。另外也需要安裝node和express的類型聲明。安裝的時候帶上- D參數來確保它是開發依賴。

yarn?add?-D?typescript?@types/express?@types/node

安裝好之后,還有一點值得注意,我們并不想每次代碼更改之后還需要手動去執行編譯才生效。這樣體驗太不好了!所以我們需要額外添加幾個依賴:

  • ts-node: 這個安裝包是為了不用編譯直接運行typescript代碼,這個對本地開發太有必要了

  • nodemon:這個安裝包在程序代碼變更之后自動監聽然后重啟開發服務。搭配ts-node模塊就可以做到編寫代碼及時生效。

因此這兩個依賴都是在開發的時候需要的,而不需編譯進生產環境的。

yarn?add?-D?ts-node?nodemon

配置我們的程序運行起來

配置Typescript文件

為我們將要用的typescript設置配置文件,創建tsconfig.json文件

touch?tsconfig.json

現在讓我們給配置文件添加編譯相關的配置參數:

  • module: "commonjs" — 如果使用過node的都知道,這個作為編譯代碼時將被編譯到最終代碼是必不可少的。

  • esModuleInterop: true — 這個選項允許我們默認導出的時候使用*代替導出的內容。

  • target: "es6" — 不同于前端代碼,我們需要控制運行環境,得確保使用的node版本能正確識別ES6語法。

  • rootDir: "./" — 設置代碼的根目錄為當前目錄。

  • outDir: "./build" — 最終將Typescript代碼編譯成執行的Javascript代碼目錄。

  • strict: true — 允許嚴格類型檢查。

最終tsconfig.json文件內容如下:

{"compilerOptions":?{"module":?"commonjs","esModuleInterop":?true,"target":?"es6","rootDir":?"./","outDir":?"./build","strict":?true} }

配置package.json腳本

目前還沒有 package.json文件的scripts項,我們需要添加幾個腳本:第一個是start啟動開發模式,另一個是 build打包線上環境代碼的命令。

啟動開發模式我們需要執行nodemon index.ts,而打包生產代碼,我們已經在tsconfig.json中給出了所有需要的信息,所以我們只需要執行tsc命令。

此刻下面是你package.json文件中所有的內容,也可能由于我們創建項目的時間不一樣,導致依賴的版本號不一樣。

{"dependencies":?{"express":?"^4.17.1"},"devDependencies":?{"@types/express":?"^4.17.11","@types/node":?"^14.14.22","nodemon":?"^2.0.7","ts-node":?"^9.1.1","typescript":?"^4.1.3"} }

Git配置

如果使用git來管理代碼,還需要添加.gitignore文件來忽視node_modules目錄和build目錄

touch?.gitignore

添加忽視的內容

node_modules build

至此,所有的安裝過程已經結束,比單純的無Typescript版本可能稍微復雜點。

創建我們的Express應用

讓我們來正式開始創建express應用。首先創建主文件index.ts

touch?index.ts

然后添加案例代碼,在網頁中輸出“hello world”

import?express?from?'express';const?app?=?express(); const?PORT?=?3000;app.get('/',?(req,?res)?=>?{res.send('Hello?world'); });app.listen(PORT,?()?=>?{console.log(`Express?with?Typescript!?http://localhost:${PORT}`); });

在終端命令行執行啟動命令 yarn run start

yarn?run?start

接下來會輸出以下內容:

[nodemon]?2.0.7 [nodemon]?to?restart?at?any?time,?enter?`rs` [nodemon]?watching?path(s):?*.* [nodemon]?watching?extensions:?ts,json [nodemon]?starting?`ts-node?index.ts` Express?with?Typescript!?http://localhost:3000

我們可以看到nodemon模塊已經監聽到所有文件的變更后使用ts-node index.ts命令啟動了我們的應用。我們現在可以在瀏覽器打開網址http://localhost:3000,將會看到網頁中輸出我們想要的“hello world”。

“Hello World”以外的功能

我們的 “Hello World”應用算是創建好了,但是我們不僅于此,還要添加一些稍微復雜點的功能,來豐富一下應用。大致功能包括:

  • 保存一系列的用戶名和與之匹配的密碼在內存中

  • 允許提交一個POST請求去創建一個新的用戶

  • 允許提交一個POST請求讓用戶登錄,并且接受因為錯誤認證返回的信息

讓我們一個個去實現以上功能!

保存用戶

首先,我們創建一個types.ts文件來定義我們用到的User類型。后面所有類型定義都寫在這個文件中。

touch?types.ts

然后導出定義的User類型

export?type?User?=?{?username:?string;?password:?string?};

好了。我們將使用內存來保存所有的用戶,而不是數據庫或者其它方式。根目錄下創建一個data目錄,然后在里面新建users.ts文件

mkdir?data touch?data/users.ts

現在在users.ts文件里創建一個User類型的空數組

import?{?User?}?from?"../types";const?users:?User[]?=?[];

提交新用戶

接下來我們希望向應用提交一個新用戶。我們在這里將要用到處理請求參數的中間件body-parse

yarn?add?body-parser

然后在主文件里導入并使用它

import?express?from?'express'; import?bodyParser?from?'body-parser';const?app?=?express(); const?PORT?=?3000;app.use(bodyParser.urlencoded({?extended:?false?}));app.get('/',?(req,?res)?=>?{res.send('Hello?world'); });app.listen(PORT,?()?=>?{console.log(`Express?with?Typescript!?http://localhost:${PORT}`); });

最后,我們可以在users文件里創建POST請求處理程序。 該處理程序將執行以下操作:

  • 校驗請求體中是否包含了用戶名和密碼,并且進行有效性驗證

  • 一旦提交的用戶名密碼不正確返回狀態碼為400的錯誤信息

  • 添加一個新用戶到users數組中

  • 返回一個201狀態的錯誤信息

讓我們開始,首先,在data/users.ts文件中創建一個addUser的方法

import?{?User?}?from?'../types';const?users:?User[]?=?[];const?addUser?=?(newUser:?User)?=>?{users.push(newUser); };

然后回到index.ts文件中添加一條"/users"的路由

import?express?from?'express'; import?bodyParser?from?'body-parser'; import?{?addUser?}?from?'./data/users';const?app?=?express(); const?PORT?=?3000;app.use(bodyParser.urlencoded({?extended:?false?}));app.get('/',?(req,?res)?=>?{res.send('Hello?world'); });app.post('/users',?(req,?res)?=>?{const?{?username,?password?}?=?req.body;if?(!username?.trim()?||?!password?.trim())?{return?res.status(400).send('Bad?username?or?password');}addUser({?username,?password?});res.status(201).send('User?created'); });app.listen(PORT,?()?=>?{console.log(`Express?with?Typescript!?http://localhost:${PORT}`); });

這里的邏輯不復雜,我們簡單解釋一下,首先請求體中要包含username和password兩個變量,而且使用trim()函數去除收尾的空字符,保證它的長度大于0。如果不滿足,返回400狀態和自定義錯誤信息。如果驗證通過,則將用戶信息添加到users數組并且返回201狀態回來。

注意:你有沒有發現users數組是沒有辦法知道有沒有同一個用戶被添加兩次的,我們暫且不考慮這種情況。

讓我們重新打開一個終端(不要關掉運行程序的終端),在終端里通過curl命令來發出一個POST請求注冊接口

curl?-d?"username=foo&password=bar"?-X?POST?http://localhost:3000/users

你將會在終端的命令行中發現輸出了下面的信息

User?created

然后再請求一次接口,這次password僅僅為空字符串,測試一下請求失敗的情況

curl?-d?"username=foo&password=?"?-X?POST?http://localhost:3000/users

沒有讓我們失望,成功返回了一下錯誤信息

Bad?username?or?password

登錄功能

登錄有點類似,我們從請求體中拿到username和password的值然后通過Array.find方法去users數組中查找相同的用戶名和密碼組合,返回200狀態碼說明用戶登錄成功,而401狀態碼表示用戶不被授權,登錄失敗。

首先我們在data/users.ts文件中添加getUser方法:

import?{?User?}?from?'../types';const?users:?User[]?=?[];export?const?addUser?=?(newUser:?User)?=>?{users.push(newUser); };export?const?getUser?=?(user:?User)?=>?{return?users.find((u)?=>?u.username?===?user.username?&&?u.password?===?user.password); };

這里getUser方法將會從users數組里返回與之匹配用戶或者undefined。

接下來我們將在index.ts里調用getUser方法

import?express?from?'express'; import?bodyParser?from?'body-parser'; import?{?addUser,?getUser?}?from?"./data/users';const?app?=?express(); const?PORT?=?3000;app.use(bodyParser.urlencoded({?extended:?false?}));app.get('/',?(req,?res)?=>?{res.send('Hello?word'); });app.post('/users',?(req,?res)?=>?{const?{?username,?password?}?=?req.body;if?(!username?.trim()?||?!password?.trim())?{return?res.status(400).send('Bad?username?or?password');}addUser({?username,?password?});res.status(201).send('User?created'); });app.post('/login',?(req,?res)?=>?{const?{?username,?password?}?=?req.body;const?found?=?getUser({username,?password})if?(!found)?{return?res.status(401).send('Login?failed');}res.status(200).send('Success'); });app.listen(PORT,?()?=>?{console.log(`Express?with?Typescript!?http://localhost:${PORT}`); });

現在我們還是用curl命令去請求注冊接口和登錄接口,登錄接口請求兩次,一次成功一次失敗

curl?-d?"username=joe&password=hard2guess"?-X?POST?http://localhost:3000/users #?User?createdcurl?-d?"username=joe&password=hard2guess"?-X?POST?http://localhost:3000/login #?Successcurl?-d?"username=joe&password=wrong"?-X?POST?http://localhost:3000/login #?Login?failed

沒問題,結果都按我們預想的順利返回了

探索Express類型

您可能已經發現,講到現在,好像都是一些基礎的東西,Express里面比較深的概念沒有涉及到,比如自定義路由,中間件和句柄等功能,我們現在就來重構它。

自定義路由類型

或許我們希望的是創建這樣一個標準的路由結構像下面這樣

const?route?=?{method:?'post',path:?'/users',middleware:?[middleware1,?middleware2],handler:?userSignup, };

我們需要在types.ts文件中定義一個Route類型。同時也需要從Express庫中導出相關的類型:Request,Response和NextFunction。Request表示客戶端的請求數據類型,Response是從服務器返回值類型,NextFunction則是next()方法的簽名,如果使用過express的中間件應該很熟悉。

在types.ts文件中,重新定義Route類型

export?type?User?=?{?username:?string;?password:?string?};type?Method?=|?'get'|?'head'|?'post'|?'put'|?'delete'|?'connect'|?'options'|?'trace'|?'patch';export?type?Route?=?{method:?Method;path:?string;middleware:?any[];handler:?any; };

如果你熟悉express中間件的話,你應該知道一個典型的中間件長這樣:

function?middleware(request,?response,?next)?{//?Do?some?logic?with?the?requestif?(request.body.something?===?'foo')?{//?Failed?criteria,?send?forbidden?resposnereturn?response.status(403).send('Forbidden');}//?Succeeded,?go?to?the?next?middlewarenext(); }

由此可知,一個中間件需要傳入三個參數,分別是Request,Response和NextFunction類型。因此如果需要我們創建一個Middleware類型:

import?{?Request,?Response,?NextFunction?}?from?'express';type?Middleware?=?(req:?Request,?res:?Response,?next:?NextFunction)?=>?any;

然后express已經有了一個叫RequestHandler類型,所以在這里我們只需要從express導出就好了,如果取個別名可以采用類型斷言。

import?{?RequestHandler?as?Middleware?}?from?'express';export?type?User?=?{?username:?string;?password:?string?};type?Method?=|?'get'|?'head'|?'post'|?'put'|?'delete'|?'connect'|?'options'|?'trace'|?'patch';export?type?Route?=?{method:?Method;path:?string;middleware:?Middleware[];handler:?any; };

最后我們只需要為handler指定類型。這里的handler應該是程序執行的最后一步,因此我們在設計的時候就不需要傳入next參數了,類型也就是RequestHandler去掉第三個參數。

import?{?Request,?Response,?RequestHandler?as?Middleware?}?from?'express';export?type?User?=?{?username:?string;?password:?string?};type?Method?=|?'get'|?'head'|?'post'|?'put'|?'delete'|?'connect'|?'options'|?'trace'|?'patch';export?type?Handler?=?(req:?Request,?res:?Response)?=>?any;export?type?Route?=?{method:?Method;path:?string;middleware:?Middleware[];handler:?Handler; };

添加一些項目結構

我們需要通過增加一些結構來把中間件和處理程序從index.ts文件中移除

創建處理器

我們把一些處理方法移到handlers目錄中

mkdir?handlers touch?handlers/user.ts

那么在handlers/user.ts文件中,我們添加如下代碼。和用戶注冊相關的處理代碼已經被我們從index.ts文件中重構到這里。重要的是我們可以確定signup方法滿足我們定義的Handlers類型

import?{?addUser?}?from?'../data/users'; import?{?Handler?}?from?'../types';export?const?signup:?Handler?=?(req,?res)?=>?{const?{?username,?password?}?=?req.body;if?(!username?.trim()?||?!password?.trim())?{return?res.status(400).send('Bad?username?or?password');}addUser({?username,?password?});res.status(201).send('User?created'); };

同樣,我們把創建auth處理器添加login方法

touch?handlers/auth.ts

添加以下代碼

import?{?getUser?}?from?'../data/users'; import?{?Handler?}?from?'../types';export?const?login:?Handler?=?(req,?res)?=>?{const?{?username,?password?}?=?req.body;const?found?=?getUser({?username,?password?});if?(!found)?{return?res.status(401).send('Login?failed');}res.status(200).send('Success'); };

最后也給我們的首頁增加一個處理器

touch?handlers/home.ts

功能很簡單,只要輸出文本

import?{?Handler?}?from?'../types';export?const?home:?Handler?=?(req,?res)?=>?{res.send('Hello?world'); };

中間件

現在還沒有任何的自定義中間件,首先創建一個middleware目錄

mkdir?middleware

我們將添加一個打印客戶端請求路徑的中間件,取名requestLogger.ts

touch?middleware/requestLogger.ts

從express庫中導出需要定義的中間件類型的RequestHandler類型

import?{?RequestHandler?as?Middleware?}?from?'express';export?const?requestLogger:?Middleware?=?(req,?res,?next)?=>?{console.log(req.path);next(); };

創建路由

既然我們已經定義了一個新的Route類型和自己的一些處理器,就可以把路由定義獨立出來一個文件,在根目錄創建routes.ts

touch?routes.ts

以下是該文件的所有代碼,為了演示就只給/login添加了requestLogger中間件

import?{?login?}?from?'./handlers/auth'; import?{?home?}?from?'./handlers/home'; import?{?signup?}?from?'./handlers/user'; import?{?requestLogger?}?from?'./middleware/requestLogger'; import?{?Route?}?from?'./types';export?const?routes:?Route[]?=?[{method:?'get',path:?'/',middleware:?[],handler:?home,},{method:?'post',path:?'/users',middleware:?[],handler:?signup,},{method:?'post',path:?'/login',middleware:?[requestLogger],handler:?login,}, ];

重構index.ts文件

最后也是最重要的一步就是簡化index.ts文件。我們通過一個forEach循環routes文件中聲明的路由信息來代替所有的route相關的代碼。這樣做最大的好處是為所有的路由定義了類型。

import?express?from?'express'; import?bodyParser?from?'body-parser'; import?{?routes?}?from?'./routes';const?app?=?express(); const?PORT?=?3000;app.use(bodyParser.urlencoded({?extended:?false?}));routes.forEach((route)?=>?{const?{?method,?path,?middleware,?handler?}?=?route;app[method](path,?...middleware,?handler); });app.listen(PORT,?()?=>?{console.log(`Express?with?Typescript!?http://localhost:${PORT}`); });

這樣看起來代碼結構清晰多了,架構的好處就是如此。另外有了Typescript強類型的支持,保證了程序的穩定性。

完整代碼

Github:
https://github.com/fantingsheng/express-typescript-app

總結

以上是生活随笔為你收集整理的【详细教程】教你如何使用Node + Express + Typescript开发一个应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。