夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Node基础

  • 《MySQL》学习笔记

  • Midway

    • Midway基础
      • 基础介绍
        • 面向对象(OOP + Class + IoC)
        • 函数式(FP + Function + Hooks)
      • 初始化
      • Controller
      • 处理参数
      • Service
        • 类型定义
        • 使用定义
        • 匹配 Controller
      • 模板渲染
        • 启用组件
        • 指定模板
        • 进行模板渲染
      • 错误处理
    • 洋葱模型
  • Nest

  • 其他

  • 服务端
  • Midway
夜猫子
2023-01-16
目录

Midway基础

# 基础介绍

一个基于渐进式理念研发的 Node.js 框架。

基于 TypeScript 开发,结合了面向对象(OOP + Class + IoC)与函数式(FP + Function + Hooks)两种编程范式,并在此之上支持了 Web / 全栈 / 微服务 / RPC / Socket / Serverless 等多种场景,致力于为用户提供简单、易用、可靠的 Node.js 服务端研发体验。

# 面向对象(OOP + Class + IoC)

Midway 支持面向对象的编程范式,为应用提供更优雅的架构。

下面是基于面向对象,开发路由的示例。

// src/controller/home.ts
import { Controller, Get } from '@midwayjs/decorator';
import { Context } from '@midwayjs/koa';

@Controller('/')
export class HomeController {

  @Inject()
  ctx: Context

  @Get('/')
  async home() {
    return {
      message: 'Hello Midwayjs!',
      query: this.ctx.ip
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 函数式(FP + Function + Hooks)

Midway 也支持函数式的编程范式,为应用提供更高的研发效率。

下面是基于函数式,开发路由接口的示例。

// src/api/index.ts

import { useContext } from '@midwayjs/hooks'
import { Context } from '@midwayjs/koa';

export default async function home () {
  const ctx = useContext<Context>()

  return {
    message: 'Hello Midwayjs!',
    query: ctx.ip
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 初始化

npm init midway

# 运行
npm run dev
1
2
3
4

# Controller

控制器,用于负责 解析用户的输入,处理后返回相应的结果。

controller

在 controller 目录中,新建一个 src/controller/weather.controller.ts 文件,内容如下。

import { Controller, Get } from '@midwayjs/decorator';

@Controller('/')
export class WeatherController {
  // 这里是装饰器,定义一个路由
  @Get('/weather')
  async getWeatherInfo(): Promise<string> {
    // 这里是 http 的返回,可以直接返回字符串,数字,JSON,Buffer 等
    return 'Hello Weather!';
  }
}
1
2
3
4
5
6
7
8
9
10
11

现在我们可以通过访问 /weather 接口返回数据了。

# 处理参数

通过添加 @Query 装饰器,我们可以获取到 URL 上的参数。

import { Controller, Get, Query } from '@midwayjs/decorator';

@Controller('/')
export class WeatherController {
  @Get('/weather')
  async getWeatherInfo(@Query('id') cityId: string): Promise<string> {
    return cityId;
  }
}
1
2
3
4
5
6
7
8
9
访问:http://localhost:7001/weather?id=444
返回:444
1
2

# Service

在实际项目中,Controller 一般用来接收请求参数,校验参数,不会包括特别复杂的逻辑,复杂而复用的逻辑,我们应该封装为 Service 文件。

添加一个 Service 用来获取天气信息,其中包括一个 http 请求,获取远端的数据:

// src/service/weather.service.ts
import { Provide } from '@midwayjs/decorator';
import { makeHttpRequest } from '@midwayjs/core';

@Provide()
export class WeatherService {
  async getWeather(cityId: string) {
    return makeHttpRequest(`http://www.weather.com.cn/data/cityinfo/${cityId}.html`, {
      dataType: 'json',
    });
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

信息

  • 1、makeHttpRequest 方法是 Midway 内置的 http 请求方法,更多参数请查看 文档 (opens new window)

  • 2、示例中的城市天气信息来自于中国中央气象台 API

# 类型定义

良好的类型定义可以帮助我们减少代码错误。

// src/interface.ts

// ...

export interface WeatherInfo {
  weatherinfo: {
    city: string;
    cityid: string;
    temp: string;
    WD: string;
    WS: string;
    SD: string;
    AP: string;
    njd: string;
    WSE: string;
    time: string;
    sm: string;
    isRadar: string;
    Radar: string;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 使用定义

import { Provide } from '@midwayjs/decorator';
import { makeHttpRequest } from '@midwayjs/core';
import { WeatherInfo } from '../interface';

@Provide()
export class WeatherService {
  async getWeather(cityId: string): Promise<WeatherInfo> {
    const result = await makeHttpRequest(`http://www.weather.com.cn/data/sk/${cityId}.html`, {
      dataType: 'json',
    });

    if (result.status === 200) {
      return result.data;
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

信息

  • 1、这里使用 @Provide 装饰器修饰类,便于后续 Controller 注入该类

# 匹配 Controller

修改之前的 Controller 文件。

import { Controller, Get, Inject, Query } from '@midwayjs/decorator';
import { WeatherInfo } from '../interface';
import { WeatherService } from '../service/weather.service';

@Controller('/')
export class WeatherController {

  @Inject()
  weatherService: WeatherService;

  @Get('/weather')
  async getWeatherInfo(@Query('cityId') cityId: string): Promise<WeatherInfo> {
    return this.weatherService.getWeather(cityId);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

信息

  • 1、这里使用 @Inject 装饰器注入 WeatherService,是 Midway 依赖注入的标准用法,可以查看 这里 (opens new window) 了解更多
  • 2、这里也同步修改了方法的返回值类型

到这里,我们可以请求 http://127.0.0.1:7001/weather?cityId=101010100 查看返回的结果。

# 模板渲染

Midway 对应的扩展包我们称为 “组件”,也是标准的 npm 包。

这里我们需要用到 @midwayjs/view-nunjucks 组件。

可以使用下面的命令安装。

$ npm i @midwayjs/view-nunjucks --save
1

# 启用组件

安装完成后,我们在 src/configuration.ts 文件中启用组件。

// ...
import * as view from '@midwayjs/view-nunjucks';

@Configuration({
  imports: [
    koa,
    // ...
    view
  ],
  importConfigs: [join(__dirname, './config')],
})
export class ContainerLifeCycle {
  // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

信息

  • 1、configuration 文件是 Midway 的生命周期入口文件,承担了组件开关,配置加载和生命周期管理的作用
  • 2、imports 就使用来导入(开启)组件的方法

# 指定模板

在 src/config/config.default.ts 中配置组件,指定为 nunjucks 模板。

// src/config/config.default.ts

import { MidwayConfig } from '@midwayjs/core';

export default {
  // ...
  view: {
    defaultViewEngine: 'nunjucks',
  },
} as MidwayConfig;
1
2
3
4
5
6
7
8
9
10

在根目录(非 src 里)添加模板 view/info.html 文件,内容如下:

<!DOCTYPE html>
<html>
  <head>
    <title>天气预报</title>
    <style>
      .weather_bg {
        background-color: #0d68bc; 
        height: 150px;
        color: #fff;
        font-size: 12px;
        line-height: 1em;
        text-align: center;
        padding: 10px;
      }

      .weather_bg label {
        line-height: 1.5em;
        text-align: center;
        text-shadow: 1px 1px 1px #555;
        background: #afdb00;
        width: 100px;
        display: inline-block;
        margin-left: 10px;
      }

      .weather_bg .temp {
        font-size: 32px;
        margin-top: 5px;
        padding-left: 14px;
      }
      .weather_bg sup {
        font-size: 0.5em;
      }
    </style>
  </head>
  <body>
    <div class="weather_bg">
      <div>
        <p>
          {{city}}({{WD}}{{WS}})
        </p>
        <p class="temp">{{temp}}<sup>℃</sup></p>
        <p>
          气压<label>{{AP}}</label>
        </p>
        <p>
          湿度<label>{{SD}}</label>
        </p>
      </div>
    </div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 进行模板渲染

调整 Controller 的代码,将返回 JSON 变为模板渲染。

// src/controller/weather.controller.ts
import { Controller, Get, Inject, Query } from '@midwayjs/decorator';
import { WeatherService } from '../service/weather.service';
import { Context } from '@midwayjs/koa'; // 这里 koa 是一个轻量易用的 Web 框架,需要单独引入包来作为上层框架

@Controller('/')
export class WeatherController {

  @Inject()
  weatherService: WeatherService;

  @Inject()
  ctx: Context;

  @Get('/weather')
  async getWeatherInfo(@Query('cityId') cityId: string): Promise<void> {
    const result = await this.weatherService.getWeather(cityId);
    if (result) {
      await this.ctx.render('info', result.weatherinfo);
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

到这一步,我们访问 http://127.0.0.1:7001/weather?cityId=101010100 已经可以看到渲染的模板内容了。

# 错误处理

一般来说,所有对外的调用都要做异常处理,并且将异常转变为我们自己业务的错误,这样才能有更好的体验。

为此,我们需要定义一个我们自己的业务错误,创建一个 src/error/weather.error.ts 文件。

// src/error/weather.error.ts
import { MidwayError } from '@midwayjs/core';

export class WeatherEmptyDataError extends MidwayError {
  constructor(err?: Error) {
    super('weather data is empty', {
      cause: err,
    });
    if (err?.stack) {
      this.stack = err.stack;
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
编辑 (opens new window)
上次更新: 2025/3/12 17:54:26
其他内容
洋葱模型

← 其他内容 洋葱模型→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式