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

SSR场景下如何获取主机名?跨域API域名适配问题

解决SSR环境下动态设置API域名的问题

这个场景我太熟悉了——做跨域名的前后端分离项目,本地和线上要自动切换API地址,客户端用window没问题,但一到SSR就直接报错,核心原因就是服务端压根没有window这个浏览器对象,得从服务端的请求上下文里拿主机信息才行。

下面分通用方案和主流SSR框架的具体实现来给你讲:

通用思路:区分客户端/服务端环境,分别获取主机信息

我们可以给Domain类加个判断逻辑,客户端继续用window.location,服务端则从请求对象的Host头里提取主机名:

export abstract class Domain {
  // 客户端判断是否为本地环境
  private static isClientLocal(): boolean {
    return typeof window !== 'undefined' && window.location.hostname === 'localhost';
  }

  // 服务端通过请求对象判断是否为本地环境
  private static isServerLocal(req: any): boolean {
    const host = req.headers.host || '';
    // 匹配localhost开头的主机,比如localhost:5000
    return host.startsWith('localhost');
  }

  // 对外暴露的方法,服务端调用时必须传req对象
  public static getApiDomain(req?: any): string {
    // 先判断是不是客户端环境
    if (typeof window !== 'undefined') {
      return this.isClientLocal() ? "http://localhost:5001" : "http://api.domain.com";
    }

    // 服务端环境必须传req,不然直接抛错提示
    if (!req) {
      throw new Error('请在服务端调用时传入请求对象(req)');
    }

    return this.isServerLocal(req) ? "http://localhost:5001" : "http://api.domain.com";
  }
}

然后在服务端渲染的入口里,比如Express的路由处理函数,调用的时候把req传进去:

// 举个Express SSR的例子
app.get('*', (req, res) => {
  const apiDomain = Domain.getApiDomain(req);
  // 用这个apiDomain去请求数据,再渲染页面
});

主流SSR框架的简化实现

如果你用的是Next.js、Nuxt.js这类框架,它们已经帮你封装好了请求上下文,直接拿就行:

Next.js

在getServerSideProps或者API路由里,直接从context里取req:

export async function getServerSideProps(context) {
  const apiDomain = Domain.getApiDomain(context.req);
  const apiRes = await fetch(`${apiDomain}/your-endpoint`);
  const data = await apiRes.json();

  return { props: { data } };
}

Nuxt.js

在asyncData或者serverMiddleware里,通过context.req获取请求对象:

export default {
  async asyncData(context) {
    const apiDomain = Domain.getApiDomain(context.req);
    const data = await this.$axios.$get(`${apiDomain}/your-endpoint`);
    return { data };
  }
}

额外小技巧:用环境变量简化判断

如果你的本地和线上环境是通过NODE_ENV区分的,其实可以不用判断主机名,直接用环境变量更靠谱:

// 本地开发时设置NODE_ENV=development,线上设为production
export abstract class Domain {
  public static getApiDomain(): string {
    return process.env.NODE_ENV === 'development' 
      ? "http://localhost:5001" 
      : "http://api.domain.com";
  }
}

这种方式代码更简洁,除非你有多个测试域名需要区分,否则优先用这个方案。


内容的提问来源于stack exchange,提问作者Aleksandr Albert

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:26:30