从服务器端(从另一个容器)和从客户端(浏览器)使用相同的 URL 引用 Docker 容器

Tho*_*son 6 docker docker-compose next.js

我有两个 docker 容器frontenddata-service.

frontend使用 NextJS 只是因为 NextJS 有一个方法getInitialProps()可以在服务器上运行,或者可以在访问者的浏览器中运行(我无法控制)。

getInitialProps()我需要调用一个 API 来获取页面的数据:

fetch('http://data-service:3001/user/123').then(...
Run Code Online (Sandbox Code Playgroud)

当在服务器上调用它时,API 返回正常,因为我的前端容器可以访问内部 docker 网络,因此可以使用 hostname 引用数据服务http://data-service

但是,当在客户端调用它时,它会失败(显然),因为 Docker 现在公开为http://localhost,我不能再引用http://data-service了。

如何配置 Docker 以便我可以在两个用例中使用 1 个 URL。如果可能的话,我宁愿不必弄清楚我在 NextJS 代码中所处的环境。

如果看到我的 docker-compose 有用,我将其包含在下面:

version: '2.2'
services:
  data-service:
    build: ./data-service
    command: npm run dev
    volumes:
      - ./data-service:/usr/src/app/
      - /usr/src/app/node_modules
    ports:
      - "3001:3001"
    environment:
      SDKKEY: "whatever"
  frontend:
    build: ./frontend
    command: npm run dev
    volumes:
      - ./frontend:/usr/src/app/
      - /usr/src/app/node_modules
    environment:
      API_PORT: "3000"
      API_HOST: "http://catalog-service"
    ports:
      - "3000:3000"
Run Code Online (Sandbox Code Playgroud)

gol*_*und 9

我发现的最优雅的解决方案在这篇文章中描述:Docker-compose make 2 microservices (frontend+backend) communications to other with http requests

实施示例:

next.config.js

module.exports = {
  serverRuntimeConfig: {
    // Will only be available on the server side
    URI: 'your-docker-uri:port'
  },
  publicRuntimeConfig: {
    // Will be available on both server and client
    URI: 'http://localhost:port'
  }
}
Run Code Online (Sandbox Code Playgroud)

pages/index.js

import getConfig from 'next/config';
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();
const API_URI = serverRuntimeConfig.apiUrl || publicRuntimeConfig.apiUrl;

const Index = ({ json }) => <div>Index</div>;

Index.getInitialProps = async () => {
       ...
       const res = await fetch(`${API_URI}/endpoint`);
       ...
}
Run Code Online (Sandbox Code Playgroud)