HTTP options 方法的作用是什么 ?

  • 检测服务器所支持的请求方法
    发送options方式请求在返回的请求头Allow属性中可以看到支持的请求方法
  • CORS 中的预检请求
    如果一个网站的其中的一部分接口的一部分方法支持跨域,我们可检测该方法是否可以跨域

allowedMethods 的作用

  • 代码:app.use(usersRouter.allowedMethods()) 加上它该路由都将支持options方法
  • 响应 options 方法, 告诉它所支持的请求方法
  • 若没有使用此方法使用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 三种错误
  1. 404
  2. 412
findById(ctx) {
    if(ctx.params.id * 1 >= db.length) { // 不存在id时
      ctx.throw(412, '先决条件失败, id 大于等于数组长度了')
    }
    ctx.body = { name: 'lilei' }
  }

RestfulToolkit不能用了 restful options_api


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
    }
  }
})
  1. 500
    ctx.status = err.status || err.statusCode || 500
  2. RestfulToolkit不能用了 restful options_restful api_02


  • 制造 404 , 412 , 500 三种错误来测试

使用 koa-json-error 进行错误处理

RestfulToolkit不能用了 restful options_restful_03

使用 koa-parameter 校验参数(校验前端表单)

参数不正确, 返回422
app.use(parameter(app))不仅仅是一个中间件, 可以在ctx加上方法校验, 可以全局使用,所以传入app

ctx.verifyParams({
      name: { type: 'string', required: true},
      age: { type: 'number', required: true}
    })

RestfulToolkit不能用了 restful options_api_04

补充:
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": "诚意 正心 明理 格物 致知 修身 齐家"
}