什么是REST及限制

REST的六个限制

  1. 客户-服务器

    • 关注点分离

    • 服务端专注数据存储,提升了简单性

    • 前端专注用户界面,提升了可移植性

  2. 无状态

    • 所有用户会话信息都保存在客户端
    • 每次请求必须包括所有信息,不能依赖上下文信息
    • 服务端不用保存会话信息,提升了简单性、可靠性、可见性
  3. 缓存

    • 所有服务端响应都要被标为可缓存或不可缓存
    • 减少前后端交互,提升了性能
  4. 统一接口

    • 接口设计尽可能统一通用,提升了简单性、可见性

    • 接口与实现解耦,使前后端可以独立开发迭代

  5. 分层系统

    • 每层只知道相邻的一层,后面隐藏的就不知道了
    • 客户端不知道是和代理还是真实服务器通信
    • 其他层:安全层、负载均衡、缓存层等
  6. 按需代码

    • 客户端可以下载运行服务端传来的代码(比如JS)

    • 通过減少ー些功能,简化了客户端

统一接口的限制

  1. 资源的标识
  2. 通过表述来操作资源
    • 表述就是 Representation,比如JSON、XML等

    • 客户端不能直接操作(比如SQL)服务端资源

    • 客户端应该通过表述(比如JSON)来操作资源

  3. 自描述消息
    • 每个消息(请求或响应)必须提供足够的信息让接受者理解

    • 媒体类型( application/json、 application/xml)

    • HTTP方法:GET(査)、POST(増)、DELETE(删)

    • 是否缓存: Cache-Control

  4. 超媒体作为应用状态引擎
    • 超媒体:带文字的链接

    • 应用状态:一个网页

    • 引擎:驱动、跳转

    • 合起来:点击链接跳转到另个网页

请求设计规范

  1. URI使用名词,尽量用复数,如/users

  2. URI使用嵌套表示关联关系,如/users/12/repos/5

  3. 使用正确的HTTP方法,如GET/POST/PUT/DELETE

  4. 不符合CRUD的情況:POST/action/子资源

合理的目录结构

将我们的代码放入到app文件下。

路由

将所有路由放入到routers文件夹下。例如主页路由,新建一个home.js文件

1
2
3
4
5
6
7
8
9
const Router = require('koa-router')

const router = new Router()

router.get('/', (ctx) => {
ctx.body = '主页'
})

module.exports = router

我们在routers文件中新建一个index.js文件,用于注册所有路由文件。

1
2
3
4
5
6
7
8
const fs = require('fs')
module.exports = (app) => {
fs.readdirSync(__dirname).forEach(file => {
if (file === 'index.js') return
const route = require(`./${file}`)
app.use(route.routes()).use(route.allowedMethods())
})
}

然后在入口文件引入此文件即可。

1
2
const routing = require('./routes/index')
routing(app)

控制器

新建controllers文件夹用于存放所有的控制器。例如home的控制器

1
2
3
4
5
6
class HomeCtl {
index (ctx) {
ctx.body = '<h1>这是主页</h1>'
}
}
module.exports = new HomeCtl()

在home的路由中使用这个控制器

1
2
3
const { index } = require('../controllers/home')

router.get('/', index)

增删改查应该返回什么样的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//  查询用户列表
router.get('/user', (ctx) => {
ctx.body = [{ name: '李梅' }]
})
// 获取特定用户
router.get('/user', (ctx) => {
ctx.body = { name: '李梅' }
})
// 新建用户
router.post('/:id', (ctx) => {
ctx.body = { name: '李梅' }
})
// 修改用户
router.put('/:id', (ctx) => {
ctx.body = { name: '李梅' }
})
// 删除用户
router.delete('/:id', (ctx) => {
ctx.status = 204
})