欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端中間件Midway的使用教程

 更新時間:2023年05月31日 09:27:11   作者:xiaofiy  
Midway 基于 TypeScript 開發(fā),結(jié)合了面向?qū)ο螅∣OP + Class + IoC)與函數(shù)式(FP + Function + Hooks)兩種編程范式,并在此之上支持了 Web / 全棧 / 微服務(wù) / RPC / Socket / Serverless 等多種場景,這篇文章主要介紹了前端中間件Midway的使用,需要的朋友可以參考下

一、 關(guān)于midway

Midway 是阿里巴巴 - 淘寶前端架構(gòu)團隊,基于漸進式理念研發(fā)的 Node.js 框架,通過自研的依賴注入容器,搭配各種上層模塊,組合出適用于不同場景的解決方案。
Midway 基于 TypeScript 開發(fā),結(jié)合了面向?qū)ο螅∣OP + Class + IoC)與函數(shù)式(FP + Function + Hooks)兩種編程范式,并在此之上支持了 Web / 全棧 / 微服務(wù) / RPC / Socket / Serverless 等多種場景,致力于為用戶提供簡單、易用、可靠的 Node.js 服務(wù)端研發(fā)體驗。

1. 解決什么痛點

以往的開發(fā)中,前端直接項目中直接調(diào)取后臺服務(wù)接口,就會從在過度依賴后臺數(shù)據(jù),或者只能請求服務(wù)后再到渲染層進行數(shù)據(jù)加工大大影響開發(fā)效率,或者存在多個部門協(xié)同開發(fā),接口數(shù)據(jù)格式達不到統(tǒng)一,前端數(shù)據(jù)處理任務(wù)量加重等溝通問題。

2. 期望達到什么效果

在項目/產(chǎn)品開發(fā)中存在某種中間件進行服務(wù)接口的二次加工或者轉(zhuǎn)發(fā)以達到前端所需的統(tǒng)一數(shù)據(jù)結(jié)構(gòu)。比如如下分工:
數(shù)據(jù):負責(zé)數(shù)據(jù)開發(fā),對外提供服務(wù)數(shù)據(jù)接口
后端:負責(zé)業(yè)務(wù)邏輯開發(fā),對外提供服務(wù)業(yè)務(wù)邏輯接口
中間層:根據(jù)前端需要,調(diào)用多端不同的服務(wù)接口并進行拼接、加工數(shù)據(jù),對前端提供加工后接口
前端:負責(zé)數(shù)據(jù)渲染

二、創(chuàng)建應(yīng)用并使用

1. 創(chuàng)建midway應(yīng)用

$npm init midway
選擇 koa-v3 項目進行初始化創(chuàng)建,項目名可以自定,比如 weather-sample。
現(xiàn)在可以啟動應(yīng)用來體驗下。
$ npm run dev

則創(chuàng)建了一個類似下面結(jié)構(gòu)的文件

.
├── src ## midway 項目源碼
│ └── controller ## Web Controller 目錄
│ └── home.controller.ts
├── test
├── package.json
└── tsconfig.json

整個項目包括了一些最基本的文件和目錄。
• src 整個 Midway 項目的源碼目錄,你之后所有的開發(fā)源碼都將存放于此
• test 項目的測試目錄,之后所有的代碼測試文件都在這里
• package.json Node.js 項目基礎(chǔ)的包管理配置文件
• tsconfig.json TypeScript 編譯配置文件

2. 認識Midway

2.1 目錄結(jié)構(gòu)

• controller Web Controller 目錄
• middleware 中間件目錄
• filter 過濾器目錄
• aspect 攔截器
• service 服務(wù)邏輯目錄
• entity 或 model 數(shù)據(jù)庫實體目錄
• config 業(yè)務(wù)的配置目錄
• util 工具類存放的目錄
• decorator 自定義裝飾器目錄
• interface.ts 業(yè)務(wù)的 ts 定義文件

2.2 Controller

控制器常用于對用戶的請求參數(shù)做一些校驗,轉(zhuǎn)換,調(diào)用復(fù)雜的業(yè)務(wù)邏輯,拿到相應(yīng)的業(yè)務(wù)結(jié)果后進行數(shù)據(jù)組裝,然后返回。
在 Midway 中,控制器 也承載了路由的能力,每個控制器可以提供多個路由,不同的路由可以執(zhí)行不同的操作。

import { Controller, Get } from '@midwayjs/decorator';
@Controller('/')
export class WeatherController {
  // 這里是裝飾器,定義一個路由
  @Get('/weather')
  async getWeatherInfo(): Promise<string> {
    // 這里是 http 的返回,可以直接返回字符串,數(shù)字,JSON,Buffer 等
    return 'Hello Weather!';
  }
}

@Controller 裝飾器告訴框架,這是一個 Web 控制器類型的類,而 @Get 裝飾器告訴框架,被修飾的 home 方法,將被暴露為 / 這個路由,可以由 GET 請求來訪問
通過訪問 /weather 接口返回數(shù)據(jù)了;整個方法返回了一個字符串,在瀏覽器中你會收到 text/plain 的響應(yīng)類型,以及一個 200 的狀態(tài)碼。

2.3 路由

上面創(chuàng)建了一個 GET 路由。一般情況下,我們會有其他的 HTTP Method,Midway 提供了更多的路由方法裝飾器。
例如:

import { Controller, Get, Post } from '@midwayjs/decorator';
@Controller('/')
export class HomeController {
  @Get('/')
  async home() {
    return 'Hello Midwayjs!';
  }
  @Post('/update')
  async updateData() {
    return 'This is a post method'
  }
}

Midway 還提供了其他的裝飾器, @Get 、 @Post 、 @Put() 、@Del() 、 @Patch() 、 @Options() 、 @Head() 和 @All() ,表示各自的 HTTP 請求方法。
@All 裝飾器比較特殊,表示能接受以上所有類型的 HTTP Method。
你可以將多個路由綁定到同一個方法上。

@Get('/')
@Get('/main')
async home() {
  return 'Hello Midwayjs!';
}

返回內(nèi)容類型將定義的內(nèi)容放在 src/interface.ts 文件中
例如:

export interface User {
  id: number;
  name: string;
  age: number;
}

使用:下方粗下劃線處

import { Controller, Get, Query } from "@midwayjs/decorator";
@Controller('/api/user')
export class UserController {
  @Get('/')
  async getUser(@Query('id') id: string): Promise<User> {
    // xxxx
  }
}

2.4 獲取請求參數(shù)

請求的數(shù)據(jù)一般都是動態(tài)的,會在 HTTP 的不同位置來傳遞,比如常見的 Query,Body 等。

第一種 query
@Query 裝飾器的有參數(shù),可以傳入一個指定的字符串 key,獲取對應(yīng)的值,賦值給入?yún)?,如果不傳入,則默認返回整個 Query 對象。

// URL = /?id=1
async getUser(@Query('id') id: string) // id = 1
async getUser(@Query() queryData) // {"id": "1"}
如果通過api獲取query中的參數(shù)
import { Controller, Get, Inject } from "@midwayjs/decorator";
import { Context } from '@midwayjs/koa';
@Controller('/user')
export class UserController {
  @Inject()
  ctx: Context;
  @Get('/')
  async getUser(): Promise<User> {
    const query = this.ctx.query;
    // {
    //   uid: '1',
    //   sex: 'male',
    // }
  }
}

注意:
當 Query String 中的 key 重復(fù)時,ctx.query 只取 key 第一次出現(xiàn)時的值,后面再出現(xiàn)的都會被忽略。
比如 GET /user?uid=1&uid=2 通過 ctx.query 拿到的值是 { uid: ‘1’ }。

第二種 body
為什么要用body’傳遞參數(shù)?
• 瀏覽器中會對 URL 的長度有所限制,如果需要傳遞的參數(shù)過多就會無法傳遞。
• 服務(wù)端經(jīng)常會將訪問的完整 URL 記錄到日志文件中,有一些敏感數(shù)據(jù)通過 URL 傳遞會不安全。
注意:
框架內(nèi)置了 bodyParser 中間件來對這兩類格式的請求 body 解析成 object 掛載到 ctx.request.body 上。HTTP 協(xié)議中并不建議在通過 GET、HEAD 方法訪問時傳遞 body,所以我們無法在 GET、HEAD 方法中按照此方法獲取到內(nèi)容。
框架對 bodyParser 設(shè)置了一些默認參數(shù),配置好之后擁有以下特性:
• 當請求的 Content-Type 為 application/json,application/json-patch+json,application/vnd.api+json 和 application/csp-report 時,會按照 json 格式對請求 body 進行解析,并限制 body 最大長度為 1mb。
• 當請求的 Content-Type 為 application/x-www-form-urlencoded 時,會按照 form 格式對請求 body 進行解析,并限制 body 最大長度為 1mb。
• 如果解析成功,body 一定會是一個 Object(可能是一個數(shù)組)。

獲取單個 body

?	// src/controller/user.ts
// POST /user/ HTTP/1.1
// Host: localhost:3000
// Content-Type: application/json; charset=UTF-8
//
// {"uid": "1", "name": "harry"}
import { Controller, Post, Body } from "@midwayjs/decorator";
@Controller('/user')
export class UserController {
  @Post('/')
  async updateUser(@Body('uid') uid: string): Promise<User> {
    // id 等價于 ctx.request.body.uid
  }
}

獲取整個 body

?	// src/controller/user.ts
// POST /user/ HTTP/1.1
// Host: localhost:3000
// Content-Type: application/json; charset=UTF-8
//
// {"uid": "1", "name": "harry"}
import { Controller, Post, Body } from "@midwayjs/decorator";
@Controller('/user')
export class UserController {
  @Post('/')
  async updateUser(@Body() user: User): Promise<User> {
    // user 等價于 ctx.request.body 整個 body 對象
    // => output user
    // {
    //   uid: '1',
    //   name: 'harry',
    // }
  }
}

從 API 獲取

?	// src/controller/user.ts
// POST /user/ HTTP/1.1
// Host: localhost:3000
// Content-Type: application/json; charset=UTF-8
//
// {"uid": "1", "name": "harry"}
import { Controller, Post, Inject } from "@midwayjs/decorator";
import { Context } from '@midwayjs/koa';
@Controller('/user')
export class UserController {
  @Inject()
  ctx: Context;
  @Post('/')
  async getUser(): Promise<User> {
    const body = this.ctx.request.body;
    // {
    //   uid: '1',
    //   name: 'harry',
    // }
  }
}

此外裝飾器還可以組合使用,獲取 query 和 body 參數(shù)

@Post('/')
async updateUser(@Body() user: User, @Query('pageIdx') pageIdx: number): Promise<User> {
  // user 從 body 獲取
  // pageIdx 從 query 獲取
}

第三種 Params
如果路由上使用 :xxx 的格式來聲明路由,那么參數(shù)可以通過 ctx.params 獲取到。
示例:從裝飾器獲取

// src/controller/user.ts
// GET /user/1
import { Controller, Get, Param } from "@midwayjs/decorator";
@Controller('/user')
export class UserController {
  @Get('/:uid')
  async getUser(@Param('uid') uid: string): Promise<User> {
    // xxxx
  }
}

示例:從 API 獲取

// src/controller/user.ts
// GET /user/1
import { Controller, Get, Inject } from "@midwayjs/decorator";
import { Context } from '@midwayjs/koa';
@Controller('/user')
export class UserController {
  @Inject()
  ctx: Context;
  @Get('/:uid')
  async getUser(): Promise<User> {
    const params = this.ctx.params;
    // {
    //   uid: '1',
    // }
  }
}

2.5 Web中間件

Web 中間件是在控制器調(diào)用 之前 和 之后(部分)調(diào)用的函數(shù)。 中間件函數(shù)可以訪問請求和響應(yīng)對象。

import { IMiddleware } from '@midwayjs/core';
import { Middleware } from '@midwayjs/decorator';
import { NextFunction, Context } from '@midwayjs/koa';
@Middleware()
export class ReportMiddleware implements IMiddleware<Context, NextFunction> {
  resolve() {
    return async (ctx: Context, next: NextFunction) => {
      // 控制器前執(zhí)行的邏輯
      const startTime = Date.now();
      // 執(zhí)行下一個 Web 中間件,最后執(zhí)行到控制器
      // 這里可以拿到下一個中間件或者控制器的返回值
      const result = await next();
      // 控制器之后執(zhí)行的邏輯
      console.log(Date.now() - startTime);
      // 返回給上一個中間件的結(jié)果
      return result;
    };
  }
  static getName(): string {
    return 'report';
  }
}

例如:

export class ErrorMiddleware implements IWebMiddleware {
    resolve() {
        return async (ctx: Context, next: IMidwayWebNext) => {
            try {
                await next()
            } catch (err: any) {
                const errorInter = RestCode.INTERNAL_SERVER_ERROR;
                console.info('錯誤信息' + err.name, err.message, err.status);
                const status = err.status || errorInter;
                // 生產(chǎn)環(huán)境時 500 錯誤的詳細錯誤內(nèi)容不返回給客戶端,因為可能包含敏感信息
                const errorMsg = status === errorInter && ctx.app.config.env === 'prod' ?
                    'Internal Server Error' :
                    err.message;
                ctx.body = {
                    code: err.name === 'ValidationError' ? RestCode.VALIDATE_ERROR : status,
                    error: errorMsg.replaceAll('\"',''),
                }
                if (status === 422) {
                    ctx.body.detail = err.errors;
                }
                ctx.status = 200
            }
            };
    }
}

全局使用中間件
所有的路由都會執(zhí)行的中間件,比如 cookie、session 等等

// src/configuration.ts
import { App, Configuration } from '@midwayjs/decorator';
import * as koa from '@midwayjs/koa';
import { ReportMiddleware } from './middleware/user.middleware';
@Configuration({
  imports: [koa]
  // ...
})
export class AutoConfiguration {
  @App()
  app: koa.Application;
  async onReady() {
    this.app.useMiddleware([ReportMiddleware1, ReportMiddleware2]);
  }
}

路由使用中間件
單個/部分路由會執(zhí)行的中間件,比如某個路由的前置校驗,數(shù)據(jù)處理等等

import { Controller } from '@midwayjs/decorator';
import { ReportMiddleware } from '../middleware/report.middlweare';
@Controller('/', { middleware: [ ReportMiddleware ] })
export class HomeController {
}

忽略和匹配路由
在中間件執(zhí)行時,我們可以添加路由忽略的邏輯。

ignore(ctx: Context): boolean {
    // 下面的路由將忽略此中間件
    return ctx.path === '/'
      || ctx.path === '/api/auth'
      || ctx.path === '/api/login';
  }

同理,也可以添加匹配的路由,只有匹配到的路由才會執(zhí)行該中間件。ignore 和 match 同時只有一個會生效。

 match(ctx: Context): boolean {
    // 下面的匹配到的路由會執(zhí)行此中間件
    if (ctx.path === '/api/index') {
      return true;
    }
  }

2.6 組件使用

參數(shù)校驗
Midway 提供了 Validate 組件。 配合 @Validate 和 @Rule 裝飾器,用來快速定義校驗的規(guī)則,幫助用戶減少這些重復(fù)的代碼。
注意:從 v3 開始,@Rule 和 @Validate 裝飾器從 @midwayjs/validate 中導(dǎo)出。
1、 安裝依賴:$ npm i @midwayjs/validate@3 –save
2、 開啟組件:
在 configuration.ts 中增加組件。

import * as validate from ‘@midwayjs/validate';
import { join } from ‘path';
@Configuration({
imports: [ validate],
importConfigs: [join(__dirname, ‘./config')],
})
}

3、 定義檢查規(guī)則:
為了方便后續(xù)處理,我們將 user 放到一個 src/dto 目錄中。
例如:

// src/dto/user.ts
import { Rule, RuleType } from ‘@midwayjs/validate';
export class UserDTO {
@Rule(RuleType.number().required())
id: number;
@Rule(RuleType.string().required())
firstName: string;
@Rule(RuleType.string().max(10))
lastName: string;
@Rule(RuleType.number().max(60))
age: number;
}

4、 應(yīng)用:
定義完類型之后,就可以直接在業(yè)務(wù)代碼中使用了,開啟校驗?zāi)芰€需要 @Validate 裝飾器。

// src/controller/home.ts
import { Controller, Get, Provide } from ‘@midwayjs/decorator';
import { UserDTO } from ‘./dto/user';
@Controller(‘/api/user')
export class HomeController {
@Post(‘/')
async updateUser(@Body() user: UserDTO ) {
// user.id
}
}

Swagger-ui
基于最新的 OpenAPI 3.0.3 實現(xiàn)了新版的 Swagger 組件。
1、 安裝依賴:
npm install @midwayjs/swagger@3 --save
npm install swagger-ui-dist --save-dev
2、 開啟組件:

import { Configuration } from ‘@midwayjs/decorator';
import * as swagger from ‘@midwayjs/swagger';
@Configuration({
imports: [
{
component: swagger,
enabledEnvironment: [‘local'] //只在 local 環(huán)境下啟用
}]})
export class MainConfiguration {
}

然后啟動項目,訪問地址:
• UI: http://127.0.0.1:7001/swagger-ui/index.html
• JSON: http://127.0.0.1:7001/swagger-ui/index.json

2.7 服務(wù)(service)

在業(yè)務(wù)中,只有控制器(Controller)的代碼是不夠的,一般來說會有一些業(yè)務(wù)邏輯被抽象到一個特定的邏輯單元中,我們一般稱為服務(wù)(Service)。

在這里插入圖片描述

提供這個抽象有以下幾個好處:
• 保持 Controller 中的邏輯更加簡潔。
• 保持業(yè)務(wù)邏輯的獨立性,抽象出來的 Service 可以被多個 Controller 重復(fù)調(diào)用。
• 將邏輯和展現(xiàn)分離,更容易編寫測試用例。
創(chuàng)建服務(wù)
一般會存放到 src/service 目錄中。我們來添加一個 user 服務(wù)。

import { Provide, App, Inject } from '@midwayjs/decorator';
import { Application } from 'egg';
import { HttpService } from '@midwayjs/axios';
var fs = require('fs');
var path = require('path');
@Provide() //拋出服務(wù)
export class UserService {
  @App()
  app: Application;
  @Inject() //依賴注入
  httpService: HttpService;
 async getUser(options: any) {
    const url = 'https://172.30.154.46:9998/samp/v1/auth/login';
    const { data } = await this.httpService.post(url, options);
    return data;
  }
}

使用服務(wù)

在 Controller 處,我們需要來調(diào)用這個服務(wù)。傳統(tǒng)的代碼寫法,我們需要初始化這個 Class(new),然后將實例放在需要調(diào)用的地方。在 Midway 中,你不需要這么做,只需要編寫我們提供的 “依賴注入” 的代碼寫法。

import { Inject, Controller, Get, Provide, Query } from '@midwayjs/decorator';
import { UserService } from '../service/user';
@Controller('/api/user')
export class APIController {
  @Inject()//引入服務(wù)
  userService: UserService;
  @Get('/')
  async getUser(@Query('id') uid) {
    const user = await this.userService.getUser(uid);
    return {success: true, message: 'OK', data: user};
  }
}

三、寫到最后

Midway 框架是在內(nèi)部已經(jīng)使用使用 5 年以上的 Node.js 框架,有著長期投入和持續(xù)維護的團隊做后盾,已經(jīng)在每年的大促場景經(jīng)過考驗,穩(wěn)定性無須擔心,并且有著豐富的組件和擴展能力,例如數(shù)據(jù)庫,緩存,定時任務(wù),進程模型,部署以及 Web,Socket 甚至 Serverless 等新場景的支持。一體化調(diào)用方案可以方便快捷和前端頁面協(xié)同開發(fā)和良好的 TypeScript 定義支持。
所以在項目中應(yīng)用Midway, 能夠為應(yīng)用提供更優(yōu)雅的架構(gòu)。

到此這篇關(guān)于前端中間件Midway的使用的文章就介紹到這了,更多相關(guān)Midway的使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論