Midway.js探索与实践

news2025/1/12 6:00:47

您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~

前言

我司的技术基建在Midway之上,主要是面向中后台前后端一体化方案,大白话就是全栈应用解决方案,什么是Midway呢?

Midway Serverless 是用于构建 Node.js 云函数的 Serverless 框架。帮助您在云原生时代大幅降低维护成本,更专注于产品研发,而其专注于函数即服务,你只需要编写JavaScript函数就可以像编写Java接口一样的简单,并且提供了开箱即用的部署解决方案。

多编程范式

Midway支持面向对象与函数式两种编程范式,你可以根据实际研发的需要,选择不同的编程范式来开发应用。

从官网中搬移两种案例,相同的hello midway接口编写,是这样的:

面向对象(OOP + Class + IoC)

面向对象写法,采用类+装饰器的形式,可能看起来有点陌生~

// src/controller/home.ts  
import { Controller, Get } from '@midwayjs/core';  
import { Context } from '@midwayjs/koa';  
  
@Controller('/')  
export class HomeController {  
  
    @Inject()  
    ctx: Context  
  
    @Get('/')  
    async home() {  
        return {  
            message: 'Hello Midwayjs!',  
            query: this.ctx.ip  
        }  
    }  
}

函数式(FP + Function + Hooks)

React很相像的一种写法~

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  
    }  
}

本文将以OOP + Class + IoC的形式来进行实践演示。

初始化构建项目

只需要两行命令,即可启动一个Midway项目,你可以理解为一个启动一个后端服务。

npm init midway
npm run dev

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

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

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

这样你就可以通过前端请求的形式获取到/weather接口了。

就像这样:

fetch('http://127.0.0.1/weather').then(res => {
    res.json().then(data => {
        console.log(data);    // Hello Weather
    })
})

对于@Controller你可以理解为一个后端项目通过一个控制器来启动一个个接口,在里面包含了许多模块的服务,如user类、list类、upload类等等,而user中可能包含注册、登录、注销;upload中可能包含上传、删除图片等等,所以你的接口看起来会像是这样的:

controller.ts

import { Controller, Post, Inject, Query, Get } from '@midwayjs/core';
import { UserService } from './service/user.service';
import { ListService } from './service/list.service';

@Controller('/')
export class CommonController {
  @Inject()
  ctx;

  @Inject()
  UserService: UserService;

  @Inject()
  ListService: ListService;
  
  @Inject()
  UploadService: UploadService;

  @Post('/register')
  async register(@Query('userId') userId: string, @Query('password') password: string): Promise<boolean> {
    return this.UserService.register({userId, password});
  }
  @Get('/getUserInfo')
  async getUserInfo() {
    return this.UserService.getUserInfo();
  }
  // List和Upload的接口...
}

user.service.ts

import { Provide, Inject, Context } from '@midwayjs/core';

interface UserInfo {
    userName: string;
    age: number;
    sex: string;
}

@Provide()
export class UserService {
  @Inject()
  ctx: Context;
  async register(params): Promise<boolean> {
    // 注册逻辑
    return true;
  }
  async getUserInfo(): Promise<UserInfo> {
    // 获取用户信息逻辑
    return {
        userName: '量子前端',
        age: 20,
        sex: '不详'
    };
  }
}

看起来有没有感受到编写一个接口就像是写一个函数/类一样简单呢?并且Midway还提供了很多强大的功能,如中间件、组件、Http服务等等,接下来我们实践两个全栈场景,分别是图片上传和验证码,来具体感受一下。

案例

图片上传

首先安装依赖包。

npm i @midwayjs/upload@3 --save

configuration.ts中导入:

@Configuration({
  imports: [upload],
  importConfigs: [
    {
      default: defaultConfig,
      prod: prodConfig,
    },
  ],
  conflictCheck: true,
})

接下来在控制器中声明并引用接口:

controller.ts

import { Controller, Post, Inject, Files } from '@midwayjs/core';
import { UploadService } from './service/upload.service';

@Controller('/')
export class CommonController {
  @Inject()
  UploadService: UploadService;
  
  @Post('/upload')
  async upload(@Files() files): Promise<string[]> {
    return this.UploadService.upload(files);
  }
}

upload.service.ts

官方有文件上传和流上传两种模式,这里以文件上传的方式将图片保存在Midway项目的public目录中。

import { Provide, Inject, Context } from '@midwayjs/core';
import * as path from 'path';
import * as moment from 'moment';
import * as uuid from 'uuid';
import * as fs from 'fs';

@Provide()
export class UploadService {
  @Inject()
  ctx: Context;
  
  async upload(files): Promise<string[]> {
    const fileDir = path.join(this.ctx.app.getBaseDir(), '..', 'public');
    const timeDir = `${moment().format('YYYY')}/${moment().format('MM-DD')}`;
    const url = path.join(fileDir, timeDir);
    const fileList = [];
    if (!fs.existsSync(url)) fs.mkdirSync(url, { recursive: true });
    for (let i = 0; i < files.length; i++) {
      const file = files[i];
      const extname: string = path.extname(file.filename).toLowerCase();
      const data = fs.readFileSync(file.data);
      const fileName = uuid.v1();
      const target = path.join(url, `${fileName}${extname}`);
      fs.writeFileSync(target, data);
      fileList.push(`${url}/${fileName}${extname}`);
    }
    return fileList;
  }
}

接下来我们简单写一个前端请求来测试。

const fileUpload = (e) => {
    const formData = new FormData();
    formData.append('file', e.target.files[0]);
    console.log(e.target.files);
    console.log(360, formData);
    fetch('http://127.0.0.1:7002/upload', {
      method: 'POST',
      body: formData,
    }).then((res) => {
      res.json().then((data) => {
        // 获取到图片上传的fileList,回显在DOM中
      });
    });
}

return (
    <input type="file" onChange={fileUpload} />
)

就这样一个简单基础版本的图片上传接口就写完啦~

验证码校验

首先安装依赖包。

npm i @midwayjs/captcha@3 --save

configuration.ts中导入:

@Configuration({
  imports: [captcha],
  importConfigs: [
    {
      default: defaultConfig,
      prod: prodConfig,
    },
  ],
  conflictCheck: true,
})

然后我们声明两个接口,分别是获取验证码接口和验证码校验接口,这里以图形验证码为例:

controller.ts

import { Controller, Post, Inject, Get } from '@midwayjs/core';
import { CaptchaService } from '@midwayjs/captcha';

@Controller('/')
export class CommonController {
    @Inject()
    CaptchaService: CaptchaService;
    
    @Get('/get-image-captcha')
      async getImageCaptcha() {
        const { id, imageBase64 } = await this.CaptchaService.image({
          width: 120,
          height: 40,
          size: 6,
          type: 'number',
        });
        return {
          id, // 验证码 id
          imageBase64, // 验证码 SVG 图片的 base64 数据,可以直接放入前端的 img 标签内
        };
      }
      // 验证验证码是否正确
      @Post('/check-captcha')
      async getCaptcha() {
        const { id, answer } = this.ctx.request.body;
        const passed: boolean = await this.CaptchaService.check(id, answer);
        return passed;
      }
}

这里直接用官方的服务接口。

  • 获取验证码接口直接返回给前端一个验证码图片id和图片base64地址;
  • 校验验证码接口前端将验证的结果和获取验证码的id给后端来校验是否一致;

这里简单写一段react伪代码调试一下:

const openCheckCaptchaModal = () => {
    // 获取所有tab的商户数量,默认选中的tab不取,走列表
    fetch('http://127.0.0.1:7002/get-image-captcha').then((res) => {
      res.json().then(({ id, imageBase64 }) => {
        Modal.alert({
          content: (
            <>
              <img src={imageBase64} />
              <Form form={form}>
                <Form.Item name="captcha">
                  <Input placeholder="请输入验证码" />
                </Form.Item>
              </Form>
              <span
                onClick={() => {
                  Modal.clear();
                  openCheckCaptchaModal();
                }}
              >
                换一张
              </span>
            </>
          ),
          onConfirm: () => {
            const captcha = form.getFieldValue('captcha');
            if (captcha) {
              fetch('http://127.0.0.1:7002/check-captcha', {
                method: 'POST',
                body: JSON.stringify({
                  id,
                  answer: captcha,
                }),
                headers: {
                  'Content-Type': 'application/json',
                },
              }).then((res) => {
                res.json().then((data) => {
                  if(data) {
                      return Message.success('验证成功');
                  }
                });
              });
            }
          },
        });
      });
    });
  };

return (
    <span onClick={openCheckCaptchaModal}>验证</span>
)

前端效果:

image.png

获取验证码:

image.png

校验:

image.png

部署接口

部署接口很方便,在Midway项目中执行npm run deploy即可进入部署流程,需前置准备阿里云 or 其他服务器账号,阿里云首次部署需要accountIdaccountKeyaccountSecret

具体文档在这里:

Midway接口部署方案

总结

如果你没有Serverless相关概念,通过本文了解Midway是一个快速入门认知到概念的方式,Midway的能力有很多,可以继续在官方文档中探索。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/602028.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

freeswitch的gateway配置方案优化

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 在之前的文章中&#xff0c;我们简单介绍过gateway的三种配置方案&#xff0c;但是实际应用之后发现&#xff0c;方案中的参数设置有缺陷&#xff0c;会导致一些问题。 本文档中&#xff0c;针对具体的gateway配置问题…

linux第六七天 which find进程等

ctrlF5 //强制刷新 which ifconfig //找到ifconfig的路径 发现在/usr/sbin/ifconfig 目录下 然后 cp /usr/sbin/ifconfig /root/bin/ipconfig 就相当于自己设置了ifconfig的另外一种命令 多个条件可以使用-a(-o)连接&#xff0c;表示而且&#xff08;或者&#xff09…

Django中使用celery实现定时任务和异步任务

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、准备二、配置1.引入库2.代码编写a、在settings.py文件下添加如下代码b、在项目主目录下创建celery.py文件c、在项目的__init__.py里面添加如下代码![在这里…

【期望】Kuangbin 危险的派对 牛客期望专题班 increment of coins

4849. 危险的迷宫 - AcWing题库 题意&#xff1a; 思路&#xff1a; 本来对期望怎么想都想不通&#xff0c;后来看了大佬的题解&#xff0c;自己动手画了画&#xff0c;以及队友说的“拆分”&#xff0c;忽然间就有点懂了.... 这个说的很对&#xff0c;把期望问题看作是DAG上…

Unity中对预制体烘焙光照贴图,在其他Scene中使用或者动态生成带光照贴图的预制体

记录个人开发笔记&#xff0c;如果有大佬有更好的方法或者觉得我这个方法哪里有问题欢迎指正&#xff01; 首先说下为什么会弄预制体烘焙光照贴图&#xff0c;因为项目需求需要动态生成一个房间的&#xff0c;因此是将房间弄成预制体&#xff0c;动态生成就好了&#xff0c;这…

【Datagear】如何给Datagear追加Admin

【背景】 Datagear默认是只设置了一个Admin&#xff0c;这个Admin可以完成用户的各种管理操作&#xff0c;并且对所有数据源&#xff0c;数据集&#xff0c;图表&#xff0c;面板拥有全部编辑权限。 【问题】 只有一个Admin很多场景下不够用。但是应用设置本身没有提供追加A…

【测试人生】测试工程如何去学习接口自动化技术

一、为什么要学习自动化 提高生产力&#xff1a;自动化可以帮助您在短时间内完成重复性工作&#xff0c;从而大大提高生产力。自动化不仅减少了手动执行任务所需的时间和精力&#xff0c;还减少了出错的风险。 质量保证&#xff1a;自动化测试可以确保软件在修改后仍然按预期运…

2023 光亚展|乐鑫将携 AI、Wi-Fi 6、私有云和 Matter 方案精彩亮相

2023 广州国际照明展览会&#xff08;光亚展&#xff09;将于 6 月 9 至 12 日在广州琶洲展馆启幕。本届展会以“光未来”为主题&#xff0c;畅想未来生活方式的无限可能。乐鑫科技 (688018.SH) 将在 B 区 9.2 号厅 D55 展位&#xff0c;带来具有前瞻性的智能照明解决方案和实体…

龙芯2K1000实战开发-以太网/串口设计

文章目录 概要整体架构流程技术名词解释技术细节小结概要 本文主要针对2k1000的以太网及串口的国产化设计 整体架构流程 提示:这里可以添加技术整体架构 整体架构,以太网,使用2k1000自带的以太网mac控制器,外选用国产化PHY,国产化变压器。 整体框架,如下图,主要是器…

2023安卓逆向 -- JNI学习(从开发到反编译)

一、新建native C项目&#xff0c;填写好项目信息&#xff0c;一路下一步即可 二、创建好项目&#xff0c;直接点击运行&#xff0c;出现下面界面&#xff0c;说明我们的环境都没有问题 三、Java层调用java层函数 1、新建一个Java Class&#xff0c;命名为JavaFun 2、编写java…

维宏系统修改端口位置操作说明

1.关闭软件后找到Ncconfig.exe工具并打开 具体操作步骤 (1)桌面上鼠标点到 NcStudio鼠标右键-打开文件所在的位置如下图 (2) 在目录中找到NcConfig.exe的快捷方式&#xff08;黄色图标&#xff09; (3)打开并输入密码&#xff08;密码和软件密码一样默认初始密码ncstudio …

欧科云链:2023年5月链上安全事件盘点

一、基本信息 2023年5月安全事件约造成1800万美元损失&#xff0c;相比上月有显著下降&#xff0c;但安全事件发生频率并未减少。其中针对Jimbos Protocol的攻击造成了约750万美元损失。Arbitrum链的Swaprum项目Rug Pull造成了约300万美元的损失。此外&#xff0c;社交媒体钓鱼…

工业RFID解决方案怎么选?主要看这几项内容

如何选择适合您需求的RFID解决方案&#xff1f;通过深入了解需求、环境适应性、成本效益和供应商选择&#xff0c;您将能够更加全面地评估和选择适合自身需求的RFID解决方案。同时&#xff0c;不断与供应商和专业人员进行沟通和合作&#xff0c;可以获取更多关于特定解决方案的…

FineReport自定义排序

FineReport是帆软的报表开发工具&#xff0c;报表开发者可以用低代码的形式&#xff0c;配置出报表。主要适用于较简单的填报场景&#xff08;比如填写销售目标&#xff0c;维护项目映射关系等&#xff09;&#xff0c;用户可以在报表上填报数据&#xff0c;存储于数据库&#…

【TES605】基于Virtex-7 FPGA的高性能实时信号处理板

板卡概述 TES605是一款基于Virtex-7 FPGA的高性能实时信号处理平台&#xff0c;该平台采用1片TI的KeyStone系列多核DSP TMS320C6678作为主处理单元&#xff0c;采用1片Xilinx的Virtex-7系列FPGA XC7VX690T作为协处理单元&#xff0c;具有2个FMC子卡接口&#xff0c;各个处理节点…

PIC 使能485/422_Part2.2_激活485半双工(修订中...)

1.485底层协议辨识 黄色是PIC发出的&#xff0c;打头的字符是"\r\n\r\n"。绿色的是上位机485接口设备发送字符串“App1"的波形。波特率均为115200。上位机绿色的波形自发自收没有问题。 示波器设置为下降沿触发——485平时空闲状态&#xff0c;线路维持高电平&…

linux0.12-12-1-总体功能

[606页] 12-1 总体功能 本章所注释的程序量较大&#xff0c;但是通过第5章中对Linux源代码目录结构的分析&#xff08;参见图5-27&#xff09;&#xff0c; 可以把它们从功能上分为4个部分进行讨论。 第一部分是有关高速缓冲区的管理程序&#xff0c;主要实现了对硬盘等块设备…

隔离驱动芯片SLMi332兼容光耦隔离驱动器时的注意事项

数明深力科SLMi33x系列SLMi332是一款兼容光耦带DESAT保护功能的IGBT/SiC隔离驱动器。内置快速去饱和(DESAT) 故障检测功能、米勒钳位功能、漏极开路故障反馈、软关断功能以及可选择的自恢复模式&#xff0c;兼容光耦隔离驱动器。 SLMi33x系列SLMi332的DESAT阈值为6.5V&#xf…

Hive学习---4、函数

1、函数 1.1 函数简介 Hive会将常用的逻辑封装成函数给用户进行使用&#xff0c;类似java中的函数。 好处&#xff1a;避免用户反复写逻辑&#xff0c;可以直接拿来使用 重点&#xff1a;用户需要知道函数叫什么&#xff0c;能做什么 Hive提供了大量的内置函数&#xff0c;按…

ATTCK v13版本战术介绍——凭证访问(一)

一、引言 在前几期文章中我们介绍了ATT&CK中侦察、资源开发、初始访问、执行、持久化、提权、防御规避战术&#xff0c;本期我们为大家介绍ATT&CK 14项战术中凭证访问战术第1-6种子技术&#xff0c;后续会介绍凭证访问其他子技术&#xff0c;敬请关注。 二、ATT&C…