一个好的 RESTful API 我们从以下几个方面考虑:
协议
: 建议使用更安全的https协议域名
: 尽量部署在专属域名下面
版本
:应该将api的版本号放入URl中:
路径
: 在RESTful架构中,每个网址代表一种资源(resource),所以网址中建议不能有动词,只能有名词,而且所用的名词往往与数据库的表名对应
请求方式
: http 请求数据的方式:(7 个 HTTP 方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS)
其他
: 过滤方式、请求数据方式、返回数据方式、安全问题路由
app/router/api.js
这里演示:GET、POST、PUT、DELETE, 备注说明:这里的POST可能会有csrf验证, 我们需要针对API接口来关闭它,下面会有相关配置
'use strict';
module.exports = app => {
const { router, controller } = app;
router.get('/api/index', controller.api.default.index);
router.get('/api/productList', controller.api.default.productList);
router.post('/api/register', controller.api.default.register);
router.put('/api/editUser', controller.api.default.editUser);
router.delete('/api/deleteUser', controller.api.default.deleteUser);
};
app/router.js
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
// ...其他路由
// api接口配置
require('./router/api')(app);
};
控制器
app/controller/api/default.js
只做一些返回数据的演示
'use strict';
const Controller = require('egg').Controller;
class DefaultController extends Controller {
async index() {
this.ctx.body = "api接口"
}
//商品列表的api接口
async productList() {
let page = this.ctx.request.query.page || 1;
let pageSize = this.ctx.request.query.pageSize || 10;
const goodsResult = await this.ctx.model.Goods.find({}).skip((page - 1) * pageSize).limit(pageSize);
this.ctx.body = {
result: goodsResult
}
}
//post 增加数据
async register() {
console.log(this.ctx.request.body)
this.ctx.body = {
result: 'success_post'
}
}
//put 修改数据
async editUser() {
console.log(this.ctx.request.body)
this.ctx.body = {
result: 'success_put'
}
}
async deleteUser() {
// console.log(this.ctx.request.body);
console.log(this.ctx.request.query);
this.ctx.body = {
result: 'success_delete'
}
}
}
module.exports = DefaultController;
前端请求
这里是基于vue-resource(官方提供的vue的一个插件),当然可以使用axios, fetch-jsonp等其他库
Home.vue 片段
<template>
<!-- 所有的内容要被根节点包含起来 -->
<div id="home">
首页组件
<button @click="getData()">请求数据</button>
<br><br><br>
<button @click="doRegister()">执行注册(增加)</button>
<br><br><br>
<button @click="doEdit()">执行修改</button>
<br><br><br>
<button @click="doDelete()">执行删除</button>
</div>
</template>
<script>
export default{
data(){
return {
msg:'我是一个首页组件msg',
flag:true,
list:[]
}
},
methods:{
getData(){
//请求数据
var api='http://localhost:7001/api/productList';
this.$http.get(api).then((response)=>{
console.log(response);
},function(err){
console.log(err);
})
},
doRegister(){
var api='http://localhost:7001/api/register';
this.$http.post(api,{
username:'张三',
age:20
}).then((response)=>{
console.log(response);
},(err)=>{
console.log(err);
})
},
doEdit(){
var api='http://localhost:7001/api/editUser';
this.$http.put(api,{
username:'张三1111',
age:20
}).then((response)=>{
console.log(response);
},(err)=>{
console.log(err);
})
},
doDelete(){
var api='http://localhost:7001/api/deleteUser?_id=11111';
this.$http.delete(api).then((response)=>{
console.log(response);
},function(err){
console.log(err);
})
}
}
}
</script>
点击页面按钮测试请求,可以看到出现问题了,eggjs默认是7001的端口,而vue打开的则是8080,于是出现了跨域问题, 如下
No 'Access-Control-Allow-Origin' header is present on the requested resource. Orgin 'http://localhost:8000' is therfore not allowed access.
我们来解决这个问题,一种是使用jsonp的方式,这种只支持get请求,有局限; 一种是后台允许跨域
下面我们来配置后台支持跨域请求
安装插件 $ npm i egg-cors --save
配置插件
// {app_root}/config/plugin.js
exports.cors = {
enable: true,
package: 'egg-cors',
};
配置安全域名:
config.security = {
csrf: {
// 判断是否需要 ignore 的方法,请求上下文 context 作为第一个参数
ignore: ctx => {
// 屏蔽csrf验证的接口或路由
let arr = [
'/pay/ali/notify', // 接收支付宝支付post接口
'/pay/wechat/notify', // 接收微信支付post接口
];
let flag = false;
let url = ctx.request.url;
// 进行匹配
arr.some((item) => {
// 通用的路由相关 和 API相关
if (url === item || url.indexOf('/api') !== -1) {
// console.log(item);
flag = true;
return true;
}
});
return flag;
},
},
domainWhiteList: ['http://localhost:8080'] // 配置跨域 这里支持这个8080的域,这个必须配置下,即使下面 origin为* 了,也应该配置,这里是客户端的域
};
// 这个配置基于:https://www.npmjs.com/package/koa2-cors
config.cors = {
origin: '*',
allowMethods: 'GET,PUT,POST,DELETE' // 一般默认的配置都是这几个,其他有 OPTIONS,HEAD,PATCH 按需加入
};