0.8.1 • Published 7 months ago

@tobosoft/request v0.8.1

Weekly downloads
-
License
MIT
Repository
-
Last release
7 months ago

Request

总览

对比 axiosumi-requestky,本包基于 fetch 抽象的 request 工具具有以下特点/优势:

  1. fetch base; 提供更好的面向未来支持
  2. 小巧迷你, 核心实现 min+gzip 仅 ~1.5K
  3. 内置拦截器管理
  4. 拦截器支持获取全生命周期 context,方便提供更好的上下文传递
  5. 对外暴露错误类型确定,可通过 error 对象获取 context
  6. 支持 extends 快速继承一个全新 request 实例

示例:

// @/services/_internal
import { NextRequest } from "@tobosoft/request";
import { acceptReqInterceptor } from "@tobosoft/request/interceptors/acceptReqInterceptor";
import { decodeResInterceptor } from "@tobosoft/request/interceptors/decodeResInterceptor";

// AppRequest 用来封装业务逻辑
class AppRequest {
  private i: NextRequest;
  constructor() {
    this.i = new NextRequest();
    this.i.interceptors.req.use(acceptReqInterceptor);
    this.i.interceptors.res.use(decodeResInterceptor);
  }

  // 可以对常见请求方式进行一层封装,同时 避免把context暴露出来
  get<T = any>(input: string, config?: NextRequestCfg): Promise<T> {
    return this.i.request(input, { method: "get", ...config }).then((ctx) => ctx.resData);
  }
  post<T = any>(input: string, config?: NextRequestCfg): Promise<T> {
    return this.i.request(input, { method: "post", ...config }).then((ctx) => ctx.resData);
  }

  request<T>(input: string, config: NextRequestCfg): Promise<NrContext & { resData: T }> {
    if (!config.method) {
      throw new Error("request调用一定要指定method");
    }
    return this.i.request(input, config) as Promise<NrContext & { resData: T }>;
  }
}
export const request = new AppRequest();

// @/services/foo.ts
import { request } from "../_internal";

export function commonGet(params: TParam) {
  // return具体的执行逻辑
  return request.get("/foo/bar", {
    // url上 ? 号后的参数放这里
    // 支持 object 或者 URLSearchParamsURLSearchParams实例
    // 重复指定时:替换
    searchParams: { ...params },
  });
}

export function commonPost(params: TParam) {
  // return具体的执行逻辑
  return request.post("/foo/bar", {
    // 提交内容放置在json字段,提示请求实现这是一个json类型数据
    // acceptReqInterceptor 拦截器 提供该入参
    json: params,
  });
}

export function formDataPost(params: TParam) {
  // return具体的执行逻辑
  return request.post("/foo/bar", {
    // formData提交可以以对象形式直接指定,request抽象会自动转化为 FormData 实例提交
    // acceptReqInterceptor 拦截器 提供该入参
    formData: params,
  });
}

export function commonDownload(params: TParam) {
  function getFilenameFromHeaders(headers: Headers): string {
    return decodeURIComponent(
      headers.get("Content-Disposition")?.split(";")[1]?.split("=")[1] || "",
    );
  }
  function getFileNameFromResponse(res: Response): string {
    return getFilenameFromHeaders(res.headers);
  }

  /** 返回文件结构信息, 为java后端惯例实现,大部分场景都适用 */
  async function getFileInfoFromNrContext(
    res: NrContext | Promise<NrContext>,
  ): Promise<CommonServicesTypes.FileInfo> {
    const { resData, response } = await res;

    return {
      file: resData,
      filename: getFileNameFromResponse(response!),
    };
  }

  return (
    request
      // 换用 .request 方法,以便拿到整体response(及其header)
      .request("/foo/bar", {
        // .request 方法 必须指定method,按照实际情况书写即可
        method: "post",
        // 指定 accept 类型为blob,阻止自动解码、设置合适的 accept header
        accept: "blob",
        // post 请求也可以指定 searchParams
        searchParams: { ...params },

        // 可选:可指定下载回调
        onDownloadProgress(progressInfo) {
          console.log(
            // 比例,数值区间 [0,1]
            progressInfo.percent,

            // 已接收数据大小,单位字节
            progressInfo.transferred,

            // 总数,单位字节
            // 数据来源于 response.headers 中 Content-Length 字段
            progressInfo.total,
          );
        },
      })
      // getFileInfoFromNrContext 为当前系统后端惯例的定制实现,大部分场景都适用
      .then(getFileInfoFromNrContext)
  );
  // 以下是等效实现
  // .then(function (ctx) {
  //   // resData是 response.body 的内容;
  //   // 指定为 blob 时会自动调用一次 await .blob()
  //   const { resData: file, response } = ctx;

  //   const { headers } = response!;

  //   const filename = decodeURIComponent(
  //     (
  //       // 获取header中指定key
  //       headers.get("Content-Disposition")
  //         // 按照 header value 书写规则解析、获取
  //         ?.split(";")[1]?.split("=")[1]
  //     ) || ""
  //   );

  //   return {
  //     file: file,
  //     filename: filename,
  //   };
  // });
}

限制

  1. 不支持 uploadProgress

对于在 request 中放置 readableStream 的支持,各浏览器支持程度不一且兼容性较差; 如若需要新增 uploadProgress 支持,可考虑在拦截器中覆盖 fetchImpl 来实现

:EOF:

0.3.9

11 months ago

0.3.0

11 months ago

0.2.1

11 months ago

0.1.2

11 months ago

0.2.0

11 months ago

0.8.1

7 months ago

0.7.2

7 months ago

0.3.6

11 months ago

0.8.0

7 months ago

0.7.1

7 months ago

0.3.5

11 months ago

0.3.8

11 months ago

0.3.7

11 months ago

0.4.1

10 months ago

0.3.2

11 months ago

0.4.0

11 months ago

0.3.1

11 months ago

0.7.0

7 months ago

0.6.1

7 months ago

0.3.4

11 months ago

0.6.0

7 months ago

0.3.3

11 months ago

0.1.1

11 months ago

0.1.0

11 months ago