鍵.png)
ASP.NET Web API快速入門介紹
const express = require('express') // 引入express,返回一個函數(shù)
const app = express() // 執(zhí)行函數(shù),返回一個Express對象
/**
* express方法返回的對象有很多方法,例如:
* app.get()
* app.post()
* app.put()
* app.delete()
* ...
* 這些都對應(yīng)這HTTP的方法(get、post、put、delete...)
*/
app.get('/', (req, res) => {
res.send('Hello, express!')
})
app.listen(3000, () => {console.log('app runing port 3000')})
對象app
的請求處理方法接收兩個參數(shù),第一個是路徑(URL),/
代表站點的根目錄;第二個是回調(diào)函數(shù)(也叫路由句柄),當(dāng)我們應(yīng)用接受到對應(yīng)的請求并匹配對應(yīng)的路徑時,調(diào)用的方法?;卣{(diào)函數(shù)有兩個參數(shù),分別是request
代表請求對象,response
響應(yīng)對象,這兩個對象有很多屬性,request
對象的屬性可以讓我們了解請求的信息,可以先在官方文檔里查看request
對象的API。最后就是使用app.listen
方法監(jiān)聽指定的端口。使用node index.js
啟動應(yīng)用,在瀏覽器中輸入localhost:3000
進行訪問。
每一次修改node程序代碼,我們都要手工重新運行,有更好的方法,我們安裝一個node包叫nodemon
(node monitor)的縮寫,使用全局安裝方式安裝:
npm i -g nodemon
安裝后,以后運行程序就是用nodemon index.js
,啟動后,nodemon會監(jiān)測該文件夾所有文件、文件名、文件拓展名的改動,在代碼修改保存后,nodemon會自動重啟運行應(yīng)用,這樣每次修改就不用手工重啟了。
上面我們寫的web服務(wù)器監(jiān)聽的服務(wù)端口3000是寫死的,在開發(fā)環(huán)境還行,但是在生產(chǎn)環(huán)境可能就不靈了,因為當(dāng)我們把應(yīng)用發(fā)布到一個共享平臺時,應(yīng)用可用的端口是由平臺動態(tài)分配的,所以不能確定我們寫的3000是否一定有用,優(yōu)化這個問題的做法是使用環(huán)境變量
,一般的,在環(huán)境變量中管理端口的屬性是PORT
,環(huán)境變量就是在進程運行時才產(chǎn)生的變量,它是在應(yīng)用之外設(shè)置的變量,在node中,需要讀取環(huán)境變量的PORT屬性,so,為了讀取PORT屬性,我們需要使用process對象
。process
是node中的全局對象,該對象下有個屬性是env
,該屬性可以獲取系統(tǒng)設(shè)置的所有環(huán)境變量,所以我們可以使用process.env.PORT
來指定應(yīng)用的端口:
// 如果系統(tǒng)指定了PORT,就用系統(tǒng)的指定的端口,如果沒有就用3000端口
const port = process.env.PORT || 3000
// 所以上面的應(yīng)用監(jiān)聽改為
app.listen(port, () => {console.log(app runing port ${port}
)})
export PORT=5000
set PORT=5000
小結(jié)
這就是node應(yīng)用中正確設(shè)置端口的方法,需要先嘗試讀取環(huán)境變量的值,如果有,就用環(huán)境變量里的值,沒有就用設(shè)置的端口。
這一小節(jié)我們講解在Express中處理get、post、put、delete請求,我們可以使用Postman
來測試我們創(chuàng)建的服務(wù),Postman
使用簡單,可以自行在網(wǎng)上搜索使用。
我們以電影為例,首先創(chuàng)建一個RESTful服務(wù),獲取所有電影列表(暫時不涉及數(shù)據(jù)庫操作,數(shù)據(jù)保存在內(nèi)存中,后面再講數(shù)據(jù)庫):
const express = require('express')
const app = express()
const port = process.env.PORT || 3000
let videos = [
{id: 1, name: 'movie1'},
{id: 2, name: 'movie2'}
]
// 獲取所有電影列表
app.get('/api/videos', (req, res) => {
res.send(videos)
})
app.listen(port, () => { console.log(Listening on port ${port}
) })
如果需要獲取單個電影數(shù)據(jù),就需要在url中包含電影的id,所以,如果想獲取id為1
的電影,url應(yīng)該是這樣的:/api/videos/1
。1是電影的id,我們的應(yīng)用中就應(yīng)該這樣寫:
// :id表示參數(shù),id是參數(shù)名,也可以叫別的名字
// 也可以指定多個參數(shù),例如:/api/videos/:year/:month/:day
app.get(/api/videos/:id
, (req, res) => {
// req.params.id 獲取路由參數(shù)(String類型)
// 從電影列表中查找到指定單個電影
let video = videos.find(v => v.id === parseInt(req.params.id))
// 沒有找到,返回404,這是RESTful的慣例
if (!video) return res.status(404).send('no hava this video')
res.send(video) // 返回指定的單個電影數(shù)據(jù)
})
使用查詢字符串向后端服務(wù)傳遞額外的參數(shù),例如url為:https//www.zkk-pro/api/videos/1?name=movie1
,表示獲取id為1的電影數(shù)據(jù),并且電影名字叫movie1的,我們用參數(shù)提供路由必要的值,使用查詢字符串傳遞額外的內(nèi)容,獲取查詢字符串的方法是:
app.get(/api/videos/:id
, (req, res) => {
res.send(req.query) // 獲取查詢字符串
})
前面我們講了處理HTTP的get請求,我們用get處理了獲取所有數(shù)據(jù)和單一數(shù)據(jù)的請求,現(xiàn)在讓我們來看看如何處理post請求,我們使用post請求來創(chuàng)建新數(shù)據(jù)。具體步驟如下:
要讀取請求體中的數(shù)據(jù),需要打開Express獲取請求體中JSON對象的功能(這個功能默認(rèn)是關(guān)閉的)
主要代碼如下:
app.use(express.json()) // 開啟Express讀取請求體JSON數(shù)據(jù)功能
// 處理post請求
app.post('/api/videos', (req, res) => {
let video = {
id: videos.length + 1, // 因為沒有用數(shù)據(jù)庫,所以手工設(shè)置id
name: req.body.name
}
videos.push(video)
// 最后,按照慣例,我們應(yīng)該返回新創(chuàng)建的數(shù)據(jù),有可能客戶端需要用到它
res.send(video)
})
app.use(express.json())
看起來有點陌生,沒關(guān)系,我們會在后面的中間件章節(jié)
中講解,當(dāng)我們調(diào)用express.json()
這個方法時,返回一個中間件,然后使用app.use
方法在處理請求流程中使用這個中間件。編寫完成后,我們可以在Chrome中添加Postman
這個插件來請求我們的post接口:
從安全角度考慮,永遠(yuǎn)不要相信客戶端發(fā)給你的東西,記住永遠(yuǎn)要驗證輸入的內(nèi)容,所以上面的post請求,我們應(yīng)該增加驗證:
// 驗證輸入
// 處理post請求
app.post('/api/videos', (req, res) => {
// 驗證輸入
if (!req.body.name || req.body.name.length < 3) {
// 返回:400 狀態(tài)碼,表示 Bad Request,是一個錯誤的請求
res.status(400).send('Name is required and should be minimum 3 characaters')
return
}
let video = {
id: videos.length + 1, // 因為沒有用數(shù)據(jù)庫,所以手工設(shè)置id
name: req.body.name
}
videos.push(video)
// 最后,按照慣例,我們應(yīng)該返回新創(chuàng)建的數(shù)據(jù),有可能客戶端需要用到它
res.send(video)
})
在現(xiàn)實開發(fā)中,面對復(fù)雜的應(yīng)用,很可能代碼比這個復(fù)雜的多,如果你不想在最開始的時候就手寫這么復(fù)雜輸入驗證邏輯,有一個可以輕松驗證輸入的包:joi
,讓我們看看如何使用joi
:
npm i joi
在使用Joi之前,要先定義一個schema(模式),schema定義了對象外觀的特征,比如對象中應(yīng)該有什么屬性,屬性的類型是什么,最小和最大的字符數(shù)是多少,有沒有包含數(shù)字,數(shù)字的范圍是什么。。。等等,具體操作看下面代碼:
const Joi = require('joi') // 引入joi庫
// 處理post請求
app.post('/api/videos', (req, res) => {
// 使用joi 驗證輸入
// 1. 定義一個schema
const schema = {
// 表示:有一個name屬性,類型為字符串,最小長度為3,是必須的
name: Joi.string().min(3).required()
}
// 2.把請求數(shù)據(jù)和 schema 傳遞給validate方法中驗證,返回一個對象
const result = Joi.validate(req.body, schema)
// 查看結(jié)果,在發(fā)起post請求時,試試合法和不合法的參數(shù),然后查看result是什么
// 如果合法,error 為null,不合法,error的值是具體的錯誤信息
console.log(result)
// { error: null,
// value: { name: '123' },
// then: [Function: then],
// catch: [Function: catch] }
// 3.判斷是否有合法(error不為null表示數(shù)據(jù)有誤),那么就返回400和錯誤信息
if (result.error) return res.status(400).send(result.error.details[0].message)
// 添加數(shù)據(jù)
let video = {
id: videos.length + 1, // 因為沒有用數(shù)據(jù)庫,所以手工設(shè)置id
name: req.body.name
}
videos.push(video)
// 最后,按照慣例,我們應(yīng)該返回新創(chuàng)建的數(shù)據(jù),有可能客戶端需要用到它
res.send(video)
})
小結(jié)
對于客戶端發(fā)過來的數(shù)據(jù),一定要進行驗證,使用joi
庫可以簡單且直觀的進行驗證,joi
還提供了很多其它驗證功能,具體的可以在使用到的時候查看官方GitHub。
要對已有數(shù)據(jù)進行更改,應(yīng)當(dāng)使用put請求
進行更新數(shù)據(jù),下面讓我們看看如何使用put
請求更新數(shù)據(jù):
app.put('/api/videos/:id', (req, res) => {
// 1. 找到指定id的電影,如果存在,返回404
let video = videos.find(v => v.id === parseInt(req.params.id))
if (!video) return res.status(404).send('The video is not found')
// 2. 驗證傳遞過來的電影對象(數(shù)據(jù)),如果不合法,返回400
const schema = {
name: Joi.string().min(3).required()
}
const { error }= Joi.validate(req.body, schema)
if (error) return res.status(400).send(error.details[0].message)
// 3.更新電影數(shù)據(jù),返回更新后的電影數(shù)據(jù)
video.name = req.body.name
res.send(video)
})
到目前為止,我們實現(xiàn)了增、查和改操作,接下來我們看看刪除操作,它跟之前的操作非常相似,具體代碼如下:
// 刪除操作
app.delete('/api/videos/:id', (req, res) => {
// 1. 根據(jù)參數(shù) id 查找指定的電影,如果不存在返回404
let video = videos.find(v => v.id === parseInt(req.params.id))
if (!video) return res.status(404).send('The video is not found')
// 2.刪除指定的電影
let index = videos.indexOf(video)
videos.splice(index, 1)
// 3. 返回刪除的電影
res.send(video)
})
在本章節(jié)中,我們主要講解了什么是RESTful API,并且使用 Express 處理 CRUD 請求,后面我們還會涉及數(shù)據(jù)庫的操作,會越來越全面哦!感謝閱讀,希望本篇文章能讓你收獲知識O(∩_∩)O~~
本文章轉(zhuǎn)載微信公眾號@Node開發(fā)技術(shù)