最新更新时间:2021年03月16日14:54:46
《猛戳-查看我的博客地图-总有你意想不到的惊喜》
本文内容:用egg-js开发接口
编写 CRUD (create, read, update, delete)语句
- 查询数据库
//read 方案一:query+sql语句
let sql = `SELECT COUNT(*) from table1; SELECT * from table2`;
this.ctx.app.mysql.query(sql);//异步
//read 方案二:get
this.ctx.app.mysql.get('talbe1');//异步 查询一条
//read 方案三
this.ctx.app.mysql.get('talbe1',{name:'wanshaobo'});//异步 查询全表
let obj = {
where:{name: 'wanshaobo'},
orders: [['age','desc'],...],
limit: 10,
offser: 0,
}
this.ctx.app.mysql.select('talble1',obj);//异步 按照条件查询
多表查询的方案:JOIN LEFT表连接;CREATE VIEW创建视图;逐表查询(先查询到表1的id,再通过id查询表2的name,最后通过name字段查询表3的数据);
- 获取和返回接口入参和出参
@post('/getList')
async getList(){
this.ctx.request.body.name;//wanshaobo 读取前端传入接口的参数
this.ctx.request.body.age;//30 读取前端传入接口的参数
}
@get('/getList')
async getList(){
this.ctx.query.name;//wanshaobo 读取前端传入接口的参数
this.ctx.query.age;//30 读取前端传入接口的参数
}
查表操作报错记录
SELECT * from table1 WHERE is_deleted = 0 order by set_time DESC;
- 报错:
nodejs.PROTOCOL_CONNECTION_LOSTError: Connection lost: The server closed the connection.
原因:table1表中没有set_time列
通过流的形式下载文件的接口
- 文件放在了cdn上
// eggDemo/server/src/app/controller/download.ts
@get('/download')
async download() {
const url = 'https://test.cdn.com/a.js';
const res = await this.ctx.curl(url, {
streaming: true,
});
this.ctx.type = 'js';
this.ctx.body = res.res;
}
- 文件放在了egg的静态资源服务上
// eggDemo/server/src/app/controller/download.ts
// app.config.static.dir -> eggDemo/server/src/app/public
const fs = require("fs");
const path = require("path");
@get('/download')
async download() {
// @ts-ignore
const ctx = this.ctx;
const { app } = ctx;
const filePath = path.resolve(app.config.static.dir,'a.js');
this.ctx.attachment('a.js');
this.ctx.set('Content-Type', 'application/octet-stream');
this.ctx.body = fs.createReadStream(filePath);
}
Eggjs中获取http请求参数的基本方式
- get
async getUser(){
const { ctx } = this;
const { id } = ctx.query
}
- post
async getUser(){
const { ctx } = this;
const { id } = ctx.request.body;
}
- put
router.put('/update/:id', controller.home.update);
async update(){
const { ctx } = this;
const { id } = ctx.params;
}
- delete
router.delete('/del/:id', controller.home.del);
async delete(){
const { ctx } = this;
const { id } = ctx.params;
}
拼接sql语句的安全性校验
- 静态查询语句,使用 query 可以执行合法的 sql 语句,无需做安全性校验
let sql = `SELECT * from table1 WHERE is_deleted = 0`;
let result = await this.ctx.app.mysql.query(sql);
- 动态查询语句,需要对查询条件 condition 的 key和value 做安全性校验,防止sql注入
//如果key和value来自前端传入的数据,防止sql注入,需要做安全性检验
@post('/getList')
async getList(){
const { app,request } = this.ctx;
let k = request.body.key;
let v = request.body.value;
k = app.mysql.escapeId(k);
v = app.mysql.escape(v);
let condition = ` and ${k}=${v}`
let sql = `SELECT * FROM table1 WHERE is_deleted = 0 ${condition}`;
let result = await this.ctx.app.mysql.query(sql);
}
- escapeId()和escape()
insert语句和update语句返回值中的insertId不一致
//如果key和value来自前端传入的数据,防止sql注入,需要做安全性检验
@post('/save')
async saveData(){
const { app,request } = this.ctx;
let insertRes = null;
//新增一条数据
insertRes = await app.mysql.insert('table1',{name:'wanshaobo'});//insertRes.insertId是table1表新增行的主键
let updateRes = null;
//修改已有数据
updateRes = await app.mysql.update('table',{id: insertRes.insertId, name:'qinlike'});//updateRes.insertId 不是table1表中被更新的行的主键 而是上一次insert操作返回的id
}
参考资料
感谢阅读,欢迎评论^-^