Koa后端小项目编程记录(二)get、post请求

原创文章
声明:作者声明此文章为原创,未经作者同意,请勿转载,若转载,务必注明本站出处,本平台保留追究侵权法律责任的权利。
全栈老韩
全栈工程师,擅长iOS App开发、前端(vue、react、nuxt、小程序&Taro)开发、Flutter、React Native、后端(midwayjs、golang、express、koa)开发、docker容器、seo优化等。

一、前言

在上一章“项目搭建”:https://www.xinwei.ltd/article/132中,我们手动创建了一个ts的后端koa项目,实现了ts编译,并且引入了关键的koa库。

这一章我们来引入其他库,实现常见的post、get请求。

二、实现监听

koa作为后端框架,可以实现对端口port的监听,所有通过该端口的请求,都会被监听到,那么koa的监听如何实现呢,这里一个简单的举例:

app.ts 复制代码
const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {
  ctx.body = 'Hello World';
});

app.listen(3000);

我们在app.ts中写入上面的代码,我们再来看一下package.json中的执行脚本:

package.json 复制代码
...
"scripts": {
    "dev": "ts-node app.ts",
    "build": "tsc"
  },
...

从这里的脚本命令,我们知道,当我们在根目录的终端中执行npm命令:

terminal 复制代码
npm run dev

时,ts-node就会去编译app.ts文件,当编译时,实例化了koa,并且listen了3000端口,那么这个时候,程序并不会直接退出exit,而是会处于pending状态,监听着来自端口3000的消息。

上面的app.ts文件中,app.use方法是一个中间件写法,也就是说请求和响应都会经过这个中间件处理,而ctx.body被赋值'Hello World'这个字符串时,就表示任何经过3000端口的请求,都会收到'Hello World'这个字符串响应。

三、引入router库,实现一个简易get请求

在后端项目中,和前端的vue以及react都很类似,甚至在flutter中也有对应的路由概念router,哪怕在iOS的组件化之中,都是可以应用到router这样的概念。所以如果对这几个方向有过开发经验的同学,应该是可以理解router的概念的。

router这个概念在后端中也很普及,golang的项目同样也是有应用到的,所以有时候经验积累的足够多的时候,很多原理都是相通的,与诸君共勉。

我们讲正文吧,koa的router,其实就是请求的path,如何从端口监听到对应的path请求,并且对这个path请求做处理,也就是返回对应的接口响应。当你不使用router时,那么需要自己处理请求上下文中的path以及携带的请求参数。

这里我使用的是"@koa/router"这个npm包处理koa的路由请求,大家可以在npm包网站:https://www.npmjs.com/package/koa-router查看这个package。

我们在终端执行:

terminal 复制代码
npm install @koa/router

并且安装对应的type支持包:

terminal 复制代码
npm install --save-dev @types/koa__router

这样子,我们就可以做一下后端path路由,修改app.ts为:

app.ts 复制代码
var Koa = require('koa');
var Router = require('koa-router');

var app = new Koa();
var router = new Router();

router.get('/', (ctx, next) => {
  // 处理类似http://127.0.0.1:3000的get请求
  ctx.body = "Hello World";
});

app
  .use(router.routes())
  .use(router.allowedMethods());

正如这个代码注释中提到的,重新运行npm run dev时,在浏览器中输入http://127.0.0.1:3000,就可以在网页上显示字符串Hello World,那么一个简单的get请求就实现了。

四、写一个post请求

我们在上面的步骤中写了一个简单的router的get请求,这里我们发散一下思维,封装一个用户登录信息模块。

在写登录信息模块之前,我们需要定义一下响应的类型结构,用来规范我们的响应数据格式。

  1. 定义响应码code的枚举:
    error枚举
error.ts 复制代码
/**
 * 接口返回的错误码
 */
enum NetErrorCode {
  NotLogin = 401,
  ParamError = 403,
  NotFound = 404,
  Success = 200,
}

export default NetErrorCode;
  1. 定义响应返回格式:
    reponse类
response.ts 复制代码
import NetErrorCode from "./error";

/**
 * 网络请求的返回
 */
export default class NetResponse<T> {
  code: NetErrorCode;
  msg?: string;
  data?: T;

  constructor(code: NetErrorCode, data: T, msg?: string) {
    this.code = code;
    this.data = data;
    this.msg = msg;
  }
}

这里使用了泛型,可以返回对应类型的数据data.
3. 创建一个router文件夹,用来存放对不同router的请求处理:

  • 登录router:
    登录的router
router.ts 复制代码
import NetErrorCode from "../dto/error";
import NetResponse from "../dto/response";

const Router = require("@koa/router");

const router = new Router();

router.get("/", (ctx: any, next: any) => {
  console.log("请求了:", ctx);
  next();
});

router.post("/login", (ctx: any, next: any) => {
  console.log("登录信息是:", ctx.request.body);
  console.log("登录信息是--headers:", ctx.request.headers);
  ctx.body = new NetResponse<any>(NetErrorCode.Success, null, "");
});

export default router;
  • 用户router:
    user router
user.ts 复制代码
const Router = require("@koa/router");

const userRouter = new Router({
  prefix: "/user",
});

userRouter.get("/profile", (ctx: any, next: any) => {
  console.log("用户信息是--headers:", typeof next);
  ctx.body = ctx.request.body;
});

export default userRouter;

这里解释一下,user router的实例化函数中,可以创建一个前缀,就像该例子中,我们定义了一个/user前缀,然后使用这个router实现一个get请求,那么这个user router就可以处理http://127.0.0.1:3000/user/profile这样的接口请求。
4. 修改app.ts如下:

app.ts 复制代码
const Koa = require("koa");

import router from "./src/router/router";
import userRouter from "./src/router/user";

const app = new Koa();

// 根请求、login请求
app.use(router.routes()).use(router.allowedMethods());
// 用户模块
app.use(userRouter.routes()).use(userRouter.allowedMethods());

app.listen(3000);
  1. 本来到这一步,一切应该是可以正常接收get、post请求的,但。。。

当你通过postman这个软件,模拟一个请求:http://127.0.0.1:3000/login

postman的response中为空,vscode的终端输出结果是undefined,这是为何呢,原因是尽管router对koa的请求做了路由处理,但是没有对ctx做解析处理,所以我们从ctx.request.body中得到的是undefined.

那么我们开始下一步。

五、引入bodyparser库

这个库就是用来做body解析的,当然还有其他的一些库,比如koa-body,这里我们使用bodyparser库,地址是:https://www.npmjs.com/search?q=body-parser

执行终端命令:

terminal 复制代码
$ npm i @koa/bodyparser --save

修改app.ts为:

app.ts 复制代码
const Koa = require("koa");
const { bodyParser } = require("@koa/bodyparser");

import router from "./src/router/router";
import userRouter from "./src/router/user";

const app = new Koa();
app.use(bodyParser());

// 根请求、login请求
app.use(router.routes()).use(router.allowedMethods());
// 用户模块
app.use(userRouter.routes()).use(userRouter.allowedMethods());

app.listen(3000);

如代码所示,我们引入bodyParser,并且以中间件的方式进行使用,那么在对端口3000发送的任何请求,都会同步解析到ctx.request之中,这样子就能获取post携带的参数。

六、测试post携带参数请求

测试post请求
终端输出

至此,post请求和get请求的案例就实现了。

本章到此结束,下一章继续。

暂无评论,快来发表第一条评论吧