You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中从Provider获取当前服务器应用URL遇阻(AWS SES场景)

解决NestJS中动态获取应用URL配置AWS SES端点的问题

问题根源

你通过HttpAdapterHost获取的应用实例没有getUrl()方法,是因为Nest的HttpAdapter抽象层并未统一提供该方法——不同的HTTP适配器(如Express/Fastify)暴露的实例API存在差异,你直接调用的方法不属于适配器的标准接口。

针对性解决方案

1. 适配Express环境(Nest默认适配器)

Express适配器的实例是Express的app对象,需要从底层server实例提取地址信息:

const instance = httpAdapterHost.httpAdapter.getInstance();
// 获取Express的server实例
const server = instance.getServer();
// 解析监听地址
const address = server.address();
// 构建基础URL(处理0.0.0.0/::这类通配IP,替换为localhost)
const baseUrl = typeof address === 'string' 
  ? address 
  : `http://${address.address === '::' || address.address === '0.0.0.0' ? 'localhost' : address.address}:${address.port}`;
// 拼接SES端点
const endpoint = `${baseUrl}/_ses`;

2. 适配Fastify环境

Fastify适配器的实例自带address()方法,可直接获取地址信息:

const instance = httpAdapterHost.httpAdapter.getInstance();
const addressInfo = instance.address();
const baseUrl = `http://${addressInfo.address === '::' || addressInfo.address === '0.0.0.0' ? 'localhost' : addressInfo.address}:${addressInfo.port}`;
const endpoint = `${baseUrl}/_ses`;

3. 通用兼容方案(推荐)

如果需要同时支持多种适配器,可通过类型判断实现兼容:

export const AWSSesClientProvider = {
  provide: AWS_SES_CLIENT,
  useFactory: async (
    config: ConfigService,
    httpAdapterHost: HttpAdapterHost,
  ) => {
    const credentials: SESClientConfig['credentials'] = {
      accessKeyId: config.get<string>('aws.accessKeyId'),
      secretAccessKey: config.get<string>('aws.secretAccessKey'),
    };

    const region: SESClientConfig['region'] = config.get<string>('aws.region');
    const isEphemeral = config.get<string>('environment') === 'ephemeral';
    let endpoint: SESClientConfig['endpoint'];

    if (isEphemeral) {
      const adapter = httpAdapterHost.httpAdapter;
      const instance = adapter.getInstance();
      let baseUrl: string;

      // 判断适配器类型
      if (typeof instance.getServer === 'function') {
        // Express逻辑
        const server = instance.getServer();
        const address = server.address();
        baseUrl = typeof address === 'string'
          ? address
          : `http://${address.address === '::' || address.address === '0.0.0.0' ? 'localhost' : address.address}:${address.port}`;
      } else if (typeof instance.address === 'function') {
        // Fastify逻辑
        const addressInfo = instance.address();
        baseUrl = `http://${addressInfo.address === '::' || addressInfo.address === '0.0.0.0' ? 'localhost' : addressInfo.address}:${addressInfo.port}`;
      } else {
        throw new Error('不支持当前使用的HTTP适配器');
      }

      endpoint = `${baseUrl}/_ses`;
    } else {
      endpoint = config.get<string>('aws.endpoint');
    }

    const configObject: SESClientConfig = {
      region,
      ...(usesLocalstack() && { endpoint, credentials }),
    };

    return new SESClient(configObject);
  },
  inject: [ConfigService, HttpAdapterHost],
};

额外注意事项

如果临时环境是容器化部署(如K8s、Docker Compose),启动时获取的可能是容器内部IP,此时需要通过服务发现机制或注入外部访问域名来构建可用URL。也可以在第一次请求时提取req.protocol和req.hostname构建URL并缓存,供SES客户端后续使用。

内容的提问来源于stack exchange,提问作者Ernesto G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 06:33:22