Midway.js探索与实践

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

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

前言

我司的技术基建在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的能力有很多,可以继续在官方文档中探索。

目录
相关文章
|
2月前
|
数据可视化 JavaScript API
使用D3.js进行数据可视化的探索与实践
【6月更文挑战第2天】本文探讨了D3.js在数据可视化中的应用,介绍了D3.js作为JavaScript库的特性,包括数据驱动、灵活性和兼容性。实践中,涉及数据准备、创建SVG容器、数据绑定与绘制、交互与动画以及样式美化。D3.js使开发人员能高效创建动态、交互式图表,适用于多平台和设备。未来,随着数据可视化技术进步,D3.js的应用前景广阔。
|
2月前
|
JavaScript 前端开发 Shell
深入Node.js的进程与子进程:从文档到实践
深入Node.js的进程与子进程:从文档到实践
|
2月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的面向智慧教育的实习实践系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的面向智慧教育的实习实践系统附带文章源码部署视频讲解等
14 0
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的实践项目管理系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的实践项目管理系统附带文章和源代码部署视频讲解等
13 0
|
3月前
|
JavaScript Java 测试技术
返家乡”高校暑期社会实践微信小程序+springboot+vue.js附带文章和源代码设计说明文档ppt
返家乡”高校暑期社会实践微信小程序+springboot+vue.js附带文章和源代码设计说明文档ppt
28 0
|
8月前
|
JavaScript 索引
JS中数组的增删改查操作实践总结
JS中数组的增删改查操作实践总结
61 0
|
3月前
|
JavaScript 前端开发 测试技术
【JavaScript技术专栏】JavaScript模块化开发实践
【4月更文挑战第30天】JavaScript模块化开发缓解了大规模应用的复杂性,通过拆分为独立模块提升代码可维护性、可读性和可测试性。CommonJS在Node.js中用于服务器,而AMD(RequireJS)适合浏览器的异步加载。ES6模块结合两者优点,提供原生支持。实践时遵循单一职责、命名规范和依赖管理等原则,借助Webpack、RequireJS等工具提升效率。模块化是现代JavaScript不可或缺的一部分,促进团队协作和代码复用。
36 0
|
3月前
|
消息中间件 监控 JavaScript
Node.js中的微服务架构:构建与实践
【4月更文挑战第30天】本文探讨了在Node.js中构建微服务的实践,包括定义服务边界、选择框架(如Express、Koa或NestJS)、设计RESTful API、实现服务间通信(HTTP、gRPC、消息队列)、错误处理、服务发现与负载均衡,以及监控和日志记录。微服务架构能提升应用的可伸缩性、灵活性和可维护性。
|
3月前
|
数据采集 JavaScript 前端开发
利用axios库在Node.js中进行代理请求的实践
利用axios库在Node.js中进行代理请求的实践
|
3月前
|
Web App开发 JavaScript 前端开发
深入浅出:Node.js 在后端开发中的应用与实践
【2月更文挑战第13天】本文旨在探讨Node.js这一流行的后端技术如何在现代Web开发中被应用以及它背后的核心优势。通过深入分析Node.js的非阻塞I/O模型、事件驱动机制和单线程特性,我们将揭示其在处理高并发场景下的高效性能。同时,结合实际开发案例,本文将展示如何利用Node.js构建高性能、可扩展的后端服务,以及在实际项目中遇到的挑战和解决方案。此外,我们还将讨论Node.js生态系统中的重要工具和库,如Express.js、Koa.js等,它们如何帮助开发者快速搭建和部署应用。通过本文的探讨,读者将获得对Node.js在后端开发中应用的深入理解,以及如何有效利用这一技术来提升开发效率
309 2

热门文章

最新文章