Skip to content

自定义扩展指南

当官方 Client 还没有接入某些新接口时,你可以通过底层 HTTP 客户端构造自定义请求来扩展功能。

扩展方式概览

扩展方式适用场景复杂度推荐指数
继承 HTTP 客户端快速实现(推荐)⭐⭐⭐⭐⭐⭐⭐
继承客户端高自定义需求,长期使用的新接口⭐⭐⭐⭐⭐⭐⭐

继承 HTTP 客户端

获取 HTTP 客户端

typescript
import { Goofish } from "goofish-client";

const client = new Goofish({ cookie: "cookie2=xxxx" });

// 获取 Mtop  的 HTTP 客户端
const mtopHttp = client.httpClientMtop;
// 获取 Passport 的 HTTP 客户端
const passportHttp = client.httpClientPassport;

// 获取 Mtop 的配置信息
const mtopConfig = client.config.mtop;
// 获取 Passport 的配置信息
const passportConfig = client.config.passport;

Mtop 接口调用示例

typescript
import {
  BaseMtopService,
  Goofish,
  GoofishMtopResponse,
  SearchResponse,
} from "goofish-client";

class ExtendedGoofish extends BaseMtopService {
  /**
   * 获取首页推荐
   * @returns 首页推荐
   */
  public async getHomeFeed(): Promise<GoofishMtopResponse<SearchResponse>> {
    return this.request<SearchResponse>({
      api: "mtop.taobao.idlehome.home.webpc.feed",
      data: {
        itemId: "",
        pageSize: 30,
        pageNumber: 1,
        machId: "",
      },
    });
  }
}

async function main() {
  const client = new Goofish({ cookie: "cookie2=xxxx" });

  const extendedClient = new ExtendedGoofish(
    client.httpClientMtop,
    client.config
  );

  const response = await extendedClient.getHomeFeed();

  console.log(response);
}

main();

Passport 接口调用示例

typescript
import {
  BasePassportService,
  Goofish,
  GoofishPassportResponse,
  QrGenerateResponse,
} from "goofish-client";

export class ExtendedGoofish extends BasePassportService {
  /**
   * 生成二维码
   * @returns 二维码生成结果
   */
  public async generate(): Promise<
    GoofishPassportResponse<QrGenerateResponse>
  > {
    return this.request<QrGenerateResponse>({
      api: "/newlogin/qrcode/generate.do",
      method: "GET",
    });
  }
}

async function main() {
  const client = new Goofish({
    cookie: "cookie2=xxxx",
  });

  const extendedClient = new ExtendedGoofish(
    client.httpClientPassport,
    client.config
  );

  const response = await extendedClient.generate();

  console.log(response);
}

main();

继承客户端

扩展 Mtop 接口

typescript
import {
  BaseMtopService,
  Goofish,
  logger,
  LogLevel,
} from "goofish-client";
import type { GoofishMtopResponse, HomeFeedResponse } from "goofish-client";

/**
 * 方式1:继承 BaseMtopService(推荐)
 * 这种方式可以直接使用 request 方法,自动处理签名、token 管理等
 */
class CustomMtopService extends BaseMtopService {
  /**
   * 自定义接口:获取首页猜你喜欢
   */
  async getHomeFeed(): Promise<GoofishMtopResponse<HomeFeedResponse>> {
    return this.request<HomeFeedResponse>({
      api: "mtop.taobao.idlehome.home.webpc.feed",
      version: "1.0",
      data: {
        itemId: "",
        pageSize: 30,
        pageNumber: 1,
        machId: "",
      },
    });
  }
}

async function main() {
  // 创建 Goofish 客户端
  const client = new Goofish({
    cookie: "cookie2=xxxx",
    level: LogLevel.DEBUG,
  });

  // 创建自定义服务实例
  const customService = new CustomMtopService(
    client.httpClientMtop,
    client.config
  );

  // 调用自定义接口
  try {
    const homeFeed = await customService.getHomeFeed();
    logger.info("首页猜你喜欢:", homeFeed);
  } catch (error) {
    logger.error("获取首页猜你喜欢失败:", error);
  }
}

main();

扩展 Passport 接口

typescript
import {
  BasePassportService,
  Goofish,
} from "goofish-client";
import type { GoofishPassportResponse, QrGenerateResponse } from "goofish-client";

/**
 * 方式1:继承 BasePassportService(推荐)
 * 这种方式可以直接使用 request 方法
 */
class CustomPassportService extends BasePassportService {
  /**
   * 自定义接口:生成二维码
   */
  async generateQrcode(): Promise<GoofishPassportResponse<QrGenerateResponse>> {
    return this.request<QrGenerateResponse>({
      api: "/newlogin/qrcode/generate.do",
      method: "GET",
      data: {
        appName: this.config.passport.appName,
        fromSite: this.config.passport.fromSite,
      },
    });
  }
}

async function main() {
  // 创建 Goofish 客户端
  const client = new Goofish({
    cookie: "cookie2=xxxx",
  });

  // 创建自定义服务实例
  const customService = new CustomPassportService(
    client.httpClientPassport,
    client.config
  );

  // 调用自定义接口
  const response = await customService.generateQrcode();
  console.log(response);
}

main();

高级扩展

拦截器扩展

typescript
import { Goofish, LogLevel } from "goofish-client";

const client = new Goofish({
  cookie: "cookie2=xxxx", // 用户认证信息
  level: LogLevel.INFO, // 日志级别
});

// 拦截 Mtop 请求
client.httpClientMtop.getAxios().interceptors.request.use((config) => {
  console.log("request", config);
  return config;
});

// 拦截 Mtop 响应
client.httpClientMtop.getAxios().interceptors.response.use((response) => {
  console.log("response", response);
  return response;
});

// 拦截 Passport 请求
client.httpClientPassport.getAxios().interceptors.request.use((config) => {
  console.log("request", config);
  return config;
});

// 拦截 Passport 响应
client.httpClientPassport.getAxios().interceptors.response.use((response) => {
  console.log("response", response);
  return response;
});

最佳实践

1. 接口兼容性

  • 功能探测:在正式调用前先检测接口是否可用,避免不必要的错误
  • 参数验证:严格验证接口参数,确保符合服务端要求

2. 性能优化

  • 请求缓存:对频繁调用的接口实施缓存策略,减少网络请求
  • 批量请求:将多个相关请求合并,减少 HTTP 连接开销
  • 请求去重:避免短时间内发送相同请求,使用防抖或节流

3. 错误处理

  • 错误分类:区分网络错误、业务错误和系统错误,采用不同处理策略
  • 友好提示:将技术错误转换为用户可理解的提示信息
  • 错误上报:建立错误监控机制,及时发现和修复问题

4. 安全考虑

  • 敏感信息保护:不在代码中硬编码密钥、Cookie 等敏感信息
  • 输入验证:对所有用户输入进行严格验证和过滤
  • Token 管理:定期更新 Token,避免过期导致的请求失败

5. 代码组织

  • 模块化设计:按业务功能组织代码,保持单一职责原则
  • 类型安全:充分利用 TypeScript 的类型系统,减少运行时错误
  • 文档完善:为每个自定义接口编写清晰的文档和使用示例

6. 监控与日志

  • 请求日志:记录关键请求信息,便于问题排查
  • 异常告警:设置关键指标告警,快速响应异常情况
  • 日志分级:合理使用日志级别,避免日志过多或过少

基于 GPL-3.0 许可证发布