//src/config/router.js module.exports = [ ['/user/:id?', 'rest'] ];这样我们就完成了一个 RESTful 路由的初始化,这个资源的所有操作都会被映射成路由文件中对应请求方法的 Action 函数中,例如:
DELETE /user/:id 删除一位用户,对应 deleteAction 方法
//src/controller/user.js module.exports = class extends think.Controller { static get _REST() { return true; } getAction() {} postAction() {} putAction() {} deleteAction() {} }简单的了解了一些入门知识之后,下面我就讲一些我平常开发 RESTful 接口时对我有帮助的一些知识点,希望对大家开发项目会有所帮助。
DELETE /post/1 删除 id=1 的文章
mysql> DESCRIBE user; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(100) | YES | | NULL | | +-------+--------------+------+-----+---------+----------------+ 2 rows in set (0.01 sec) mysql> DESCRIBE post; +-------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | text | YES | | NULL | | +-------+---------+------+-----+---------+----------------+ 2 rows in set (0.00 sec) mysql> DESCRIBE user_post; +---------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | user_id | int(11) | NO | | NULL | | | post_id | int(11) | NO | | NULL | | +---------+---------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)作为一款约定大于配置的 Web 框架,ThinkJS 默认规定了请求 RESTful 资源的时候,会根据当前资源 URI 找到对应的资源表,比如 GET /post 会找到 post 表。然后再进行查询的之后会进行自动的关联查询。例如当你在模型里标记了 post 和 user 是一对多的关系,且 post 表中存在 user_id 字段(也就是关联表表名 + _id),会自动关联获取到 project 对应的 user 数据。这在进行数据操作的时候会节省非常多的工作量。
DELETE /token:删除凭证,用来进行登出操作
//src/logic/base.js module.exports = class extends think.Logic { async __before() { //接口 CSRF 校验 if (!this.isCli && !this.isGet) { const referrer = this.referrer(true); if (!/^xxx\.com$/.test(referrer)) { return this.fail('请不要在非其它网站中使用该接口!'); } } // 堆代码 duidaima.com // 非登录接口需要做登录校验 const userInfo = await this.session('userInfo') || {}; if(think.isEmpty(userInfo) && !/\/(?:token)\.js/.test(this.__filename)) { return this.ctx.throw(401, 'UnAuthorized'); } } } //src/logic/user.js const Base = require('./base.js'); module.exports = class extends Base {}创建一个 Base 基类,所有的 Logic 通过继承该基类就都能享受到 CSRF 和登录校验了。
//src/logic/base.js module.exports = class extends think.Logic { async __before() { const userInfo = this.session('userInfo') || {}; this.userInfo = this.ctx.state.userInfo = userInfo; if(think.isEmpty(userInfo)) { return this.ctx.throw(401); } } } //src/logic/project/base.js const Base = require('../base.js'); module.exports = class extends Base { async __before() { await super.__before(); const {team_id} = this.get(); const {id: user_id} = this.userInfo; const permission = await this.model('team_user').where({team_id, user_id}).find(); const {controller} = this.ctx; // 团队接口中只有普通用户只有权限调用获取邀请链接详细信息和接受邀请链接两个接口 if(controller !== 'team/invitation' && (this.isGet && !this.id)) { if(think.isEmpty(permission)) { return this.fail('你没有权限操作该团队'); } } this.userInfo.role_id = permission.role_id; } } //src/logic/project/user/base.js const Base = require('../base'); module.eports = class extends Base { async __before() { await super.__before(); const {role_id} = this.userInfo; if(!global.EDITOR.is(role_id)) { return this.fail('你没有权限操作该文章'); } } }通过创建三个 Base 基类,我们将权限校验进行了合理的拆分同时又能保证校验的完整性。同级别的路由只要继承当前层级的 Base 基类就能享受到通用的校验逻辑。
//src/controller/project/user/post.js module.exports = class extends think.Controller { async indexAction() { const ret = await this.model('post').where({project_id: 1}).where({user_id: 2}).select(); return this.success(ret); } }利用这个特性,我们可以对操作进行优化,在 constructor 的时候将当前 Controller 下的通用 WHERE 条件 project_id 和 user_id 传入。这样我们在其它的 Action 操作的时候就不用每个都传一变了,同时也一定规避了可能会漏传限制条件的风险。
//src/controller/project/user/post.js module.exports = class extends think.Controller { constructor(ctx) { super(ctx); const {project_id, user_id} = this.get(); this.modelInstance = this.model('post').where({project_id, user_id}); } async getAction() { const ret = await this.modelInstance.select(); return this.success(ret); } }后记