跳到主要内容

迁移指南:从 Keq v2 到 v5

· 阅读需 6 分钟
ZhiHao Guo
Keq 维护者

Keq v5 对架构进行了全面重构,这些变更虽然涉及多个方面,但大部分对用户是透明的。本指南重点关注你需要实际修改的代码部分。

为什么升级到 v5?

核心收益

  • 统一的官方生态 - 所有官方包统一在 @keq-request scope 下,版本号统一管理,更清晰的依赖关系
  • CLI 能力增强 - 代码生成工具支持插件扩展和 ignore 配置,适应更复杂的项目结构
  • 更安全的上下文对象 - 通过 getter/setter 保护,防止中间件意外修改关键状态
  • 更好的 IoC 框架集成 - KeqRequest 改为真正的类,完美支持 NestJS 等依赖注入框架的服务注入
  • 灵活的 Query 序列化 - 支持多种数组序列化方式(indices/brackets/repeat/comma),轻松适配各种后端
为什么没有 v3 和 v4?

keq 核心库的旧版本号是 v2,但是 keq-urlkeq-headerskeq-cli 等官方包各自独立维护,版本号不统一。 尤其是 keq-cli 曾发布过 v3 和 v4 版本,并带来了一些重要功能。 因此,为了统一版本号和简化用户认知,我们将下一个主要版本号定为 v5。

快速迁移步骤

按照以下步骤逐一迁移你的项目:

第一步:更新包版本和导入

package.json 中更新所有 keq 相关包到 v5,然后更新所有导入:

// ❌ v2
import request from "keq"
import { RequestException } from "keq-exception"
import { cache } from "keq-cache"

// ✅ v5
import { request } from "keq"
import { RequestException } from "@keq-request/exception"
import { cache } from "@keq-request/cache"

受影响的包列表:

v2 包名v5 包名
keq-cache@keq-request/cache
keq-headers@keq-request/headers
keq-cli@keq-request/cli
keq-url@keq-request/url
keq-exception@keq-request/exception

第二步:修复 Query 参数序列化

如果你的代码中使用了数组类型的 Query 参数,则需要指定 arrayFormat 选项以保持与 v2 行为一致:

// ❌ v2 (默认使用 brackets 格式)
request
  .get("/api")
  .query({ a: [1, 2] })

// ✅ v5 (需显式指定 brackets 格式)
request
  .get("/api")
  .query({ a: [1, 2] }, { arrayFormat: "brackets" }) 

v5 支持的所有格式:

  • indices (v5 默认) - ?ids[0]=1&ids[1]=2
  • brackets (v2 默认) - ?ids[]=1&ids[]=2
  • repeat - ?ids=1&ids=2
  • comma - ?ids=1,2
为何 v5 默认的 arrayFormat 与 v2 不一致?

keq 使用 qs 进行 Query 参数序列化。(qs 的默认数组格式是 indices) 在 v2 版本中,keq 并不支持自定义 arrayFormat,所以采用了 brackets 作为默认值以兼容大部分后端框架。 但这种做法导致了与 qs 默认行为不一致,给用户带来更多的心智负担。 因此,在 v5 中我们将默认值改为 indices,并允许用户根据需要自定义。

第三步:修复路径参数编码

request
  .get("/cats/{name}/:age") // ❌ v2 支持 :variable 和 {variable} 两种写法
  .get("/cats/{name}/{age}")  // ✅ v5 仅支持 {variable} 写法
  .params("name", "mimi")
  .params("age", 3)

第四步:更新 options

resolveWithResponse:

const response = await request
  .get("/data")
  .option("resolveWithResponse", true)      // ❌ v2
  .resolveWith("response")                  // ✅ v5

retryTimes/retryDelay/retryOn:

await request
  .get("/data")
  .options({                
    retryTimes: 3,          
    retryDelay: 1000,       
    retryOn: () => true,    
  })                        
  .options({                
    retry: {                
      times: 3,             
      delay: 1000,          
      on: () => true,       
    }                       
  })                        

第五步:修改中间件

import { KeqMiddleware } from 'keq'

// RequestException 的导入路径变更
import { RequestException } from 'keq-exception'
import { RequestException } from 'keq'

function myMiddleware(): KeqMiddleware {
  return async (context, next) => {
    // context.identifier => context.locationId
    context.identifier 
    context.locationId 

    // context.metadata => context.orchestration
    context.metadata      
    context.orchestration 

    // retryTimes/retryDelay/retryOn => retry.on/times/delay
    context.options.retryTimes 
    context.options.retryDelay 
    context.options.retryOn    
    context.data.retry.times   
    context.data.retry.delay   
    context.data.retry.on      

    // context.options.resolveWithResponse => context.options.resolveWith
    context.options.resolveWithResponse = true
    context.options.resolveWith = "response"

    // 新版本中 context.response 是只读属性
    context.response = new Response() 

    // 若要避免中间件被重试
    if (!context.data.retry?.attempt) doSomething() 
  }
}

第六步:修改 Typescript 类型

部分 TypeScript 类型名称发生了变化:

旧类型新类型
KeqOptionsKeqMiddlewareOptions
KeqOperationsKeqApiSchema
KeqBaseOperationKeqDefaultOperation

其他破坏性变更

@keq-request/cli

代码结构变更

旧的 keq-cli@4 生成的代码结构如下:

outdir
└── animal-service
    ├── components
    │   └── schemas
    │       ├── cat.ts
    │       ├── dog.ts
    │       └── index.ts
    ├── types
    │   ├── get-cat.ts
    │   └── get-dog.ts
    ├── get-cat.ts
    ├── get-dog.ts
    └── index.ts

相比旧版本,@keq-request/cli 将 请求函数聚合到 operations 目录下, 并且增加 .request.ts.schema.ts.type.ts 后缀以区分不同文件类型。 新的代码结构如下:

outdir
├── animal-service
│   ├── components
│   │   └── schemas
│   │       ├── cat.schema.ts
│   │       ├── dog.schema.ts
│   │       └── index.ts
│   ├── types
│   │   ├── get-cat.type.ts
│   │   └── get-dog.type.ts
│   └── operations
│       ├── get-cat.request.ts
│       ├── get-dog.request.ts
│       └── index.ts
└── request.ts

迁移方案

  1. 删除旧的outdir目录,

  2. 修改 .keqrc.(yml|json|js|ts) 配置

    .keqrc.ts
    import { defineKeqConfig, FileNamingStyle } from "keq-cli";           
    import { defineKeqConfig, FileNamingStyle } from "@keq-request/cli";  
    
    export default defineKeqConfig({
      outdir: './outdir',
      request: './custom_request_file_path',  
      fileNamingStyle: FileNamingStyle.snakeCase,
      modules: {
        animalService: 'http://example.com/v1/swagger.json',
      },
      qs: { arrayFormat: 'brackets' }  
    });
  3. 重新生成代码:

  4. 更新项目代码:

    // 请求函数的导入路径变更
    import { getCat } from '@outdir/animal-service'
    import { getCat } from '@outdir/animal-service/operations'
    
    import { getDog } from '@outdir/animal-service/get-dog'
    import { getDog } from '@outdir/animal-service/operations/get-dog'
    
    // request 的导入路径变更
    import { request } from 'keq'
    import { request } from '@outdir/request'

兼容性

Keq v2 仅支持 NodeJS 18+ 和主流现代浏览器,但未明确列出具体的浏览器版本; Keq v5 则补充了详细的浏览器兼容性列表:

Chrome logoChrome
Firefox logoFirefox
Safari logoSafari
Edge
Node.js
70+78+12+80+20+

Typescript

Keq v2 中,request.[method]() 的返回类型默认为 Keq<any>; Keq v5 中,返回类型默认为 Keq<unknown>,以鼓励用户显式指定类型,提升类型安全性。

const body = await request
  .get<any>("/cats") // 若不显示指定类型,返回类型默认为 Keq<unknown>