HTTP options 方法的作用是什麼 ?
- 檢測服務器所支持的請求方法
發送options方式請求在返回的請求頭Allow屬性中可以看到支持的請求方法 - CORS 中的預檢請求
如果一個網站的其中的一部分接口的一部分方法支持跨域,我們可檢測該方法是否可以跨域
allowedMethods 的作用
- 代碼:
app.use(usersRouter.allowedMethods())
加上它該路由都將支持options方法 - 響應 options 方法, 告訴它所支持的請求方法
- 若沒有使用此方法使用option方式請求就會報404錯誤
- 若沒有使用此方法使用option方式請求就會報404錯誤
- 相應的返回405(不允許)和501(沒實現)
405: 支持該請求方法但是該接口功能未實現未寫的時候
501: 不支持該請求方法是返回
RESTful API 最佳實踐–增刪改查應該返回什麼響應?
增加修改返回該對象
刪除返回204狀態碼
實例:
usersRouter.delete('/:id', (ctx) => {
ctx.status = 204
})
錯誤處理
- 編程語言或計算機硬件裏的一種機制
- 處理軟件或信息系統中出現的異常狀況
異常狀況
- 運行時錯誤, 都返回 500
建立在語法沒有錯誤的基礎上, 在運行時出現的錯誤, 如請求undefined
時錯誤 - 邏輯錯誤, 如
找不到(404) .
先決條件失敗 ( 412 ) : 請求的id
不存在
無法處理的實體 ( 參數格式不對 , 422 ) : 請求體參數格式不對
等…
爲什麼要用錯誤處理
- 防止程序掛掉
try…catch - 告訴用戶錯誤信息
避免用戶不知道錯在哪裏, 體驗較差, 用戶羣體消失 - 便於開發者調試
操作步驟
- 製造 404 , 412 , 500 三種錯誤
- 404
- 412
findById(ctx) {
if(ctx.params.id * 1 >= db.length) { // 不存在id時
ctx.throw(412, '先決條件失敗, id 大於等於數組長度了')
}
ctx.body = { name: 'lilei' }
}
3. 500
find(ctx) {
ctx.body = a.b
}
- 瞭解 Koa 自帶的錯誤處理做了什麼
自己編寫錯誤處理中間件
操作步驟
- 自己編寫錯誤處理中間件
app.use(async(ctx, next) => {
try {
await next()
} catch (err) {
// message:"先決條件失敗, id 大於等於數組長度了"
// name:"PreconditionFailedError"
// stack:"PreconditionFailedError: 先決條件失敗, id 大於等於數組長度了
// expose:true
// status:412
// statusCode:412
ctx.status = err.status || err.statusCode
ctx.body = {
message: err.message
}
}
})
- 500
ctx.status = err.status || err.statusCode || 500
- 製造 404 , 412 , 500 三種錯誤來測試
使用 koa-json-error
進行錯誤處理
使用 koa-parameter
校驗參數(校驗前端表單)
參數不正確, 返回422
app.use(parameter(app))
不僅僅是一箇中間件, 可以在ctx加上方法校驗, 可以全局使用,所以傳入app
ctx.verifyParams({
name: { type: 'string', required: true},
age: { type: 'number', required: true}
})
補充:
409
: 如新建用戶,發現用戶已存在,拋出錯誤
字段過濾
設計schema默認隱藏部分字段
原返回
{
"gender": "male",
"locations": [
"上海",
"北京"
],
"_id": "5eadafda08d7180ecc1fb330",
"username": "izhaong",
"employments": [
{
"_id": "5eadb33dfb66404e84c9fa57",
"company": "biotree"
}
],
"educations": [
{
"_id": "5eadb33dfb66404e84c9fa58",
"school": "皇家機電",
"major": "釩鈦資源利用技術",
"diploma": 3,
"entrance_year": 2014,
"graduation_year": 2017
}
],
"avatar": "http://localhost:3000/upload/upload_7fb20d056f3d693d4bde34a2b4289783.jpeg",
"business": "互聯網",
"headline": "誠意 正心 明理 格物 致知 修身 齊家"
}
設計
const userSchema = new Schema({
__v: { type: Number, select: false },
username: { type: String, required: true },
password: { type: String, required: true, select: false },
avatar: { type: String },
gender: { type: String, enum: ['male', 'femele'], default: 'male', required: true },
headline: { type: String },
locations: { type: [{ type: String }], select: false },
business: { type: String, select: false },
employments: { type: [{ company: { type: String }, job: { type: String } }], select: false },
educations: {
type: [{
school: { type: String },
major: { type: String },
diploma: { type: Number, enum: [1, 2, 3, 4, 5] },
entrance_year: { type: Number },
graduation_year: { type: Number }
}],
select: false
}
})
設計之後
{
"gender": "male",
"_id": "5eadafda08d7180ecc1fb330",
"username": "izhaong",
"avatar": "http://localhost:3000/upload/upload_7fb20d056f3d693d4bde34a2b4289783.jpeg",
"headline": "誠意 正心 明理 格物 致知 修身 齊家"
}
通過查詢字符串顯示隱藏字段
mongoose
是支持const user = await User.findById(ctx.params.id).select('+educations+business')
這種查詢的
所以我們不能寫死
處理得
const { fields } = ctx.query
// f不能爲空 過濾掉
const selectFields = fields.split(';').filter(f => f).map(f => ' +' + f).join('')
// const user = await User.findById(ctx.params.id)
// const user = await User.findById(ctx.params.id).select('+educations+business')
const user = await User.findById(ctx.params.id).select(selectFields)
查詢{{api}}/users/5eadafda08d7180ecc1fb330?fields=educations;business
得
{
"gender": "male",
"_id": "5eadafda08d7180ecc1fb330",
"username": "izhaong",
"educations": [
{
"_id": "5eadca0728cdd1bf308632de",
"school": "皇家機電",
"major": "釩鈦資源利用技術",
"diploma": 3,
"entrance_year": 2014,
"graduation_year": 2017
}
],
"avatar": "http://localhost:3000/upload/upload_7fb20d056f3d693d4bde34a2b4289783.jpeg",
"business": "互聯網",
"headline": "誠意 正心 明理 格物 致知 修身 齊家"
}