next.js 从服务器端(从另一个容器)和客户端(浏览器)引用具有相同URL的Docker容器

zujrkrfu  于 2023-10-18  发布在  Docker
关注(0)|答案(2)|浏览(96)

我有两个Docker容器frontenddata-service
frontend正在使用NextJS,这只是因为NextJS有一个名为getInitialProps()的方法,可以在服务器上运行,也可以在访问者的浏览器中运行(我对此没有控制权)。
getInitialProps()中,我需要调用一个API来获取页面的数据:

fetch('http://data-service:3001/user/123').then(...

当在服务器上调用这个函数时,API返回正常,因为我的前端容器可以访问内部Docker网络,因此可以使用主机名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"
e1xvtsh3

e1xvtsh31#

我发现的最优雅的解决方案在这篇文章中描述:Docker-compose make 2 microservices (frontend+backend) communicate to each 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'
  }
}

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`);
       ...
}
xkrw2x1b

xkrw2x1b2#

作为公认的答案,我会建议你使用it's been deprecated,但我担心。尽管如此,仍然可以获取服务器运行时配置“serverRuntimeConfig”值:
1.单位:next.config.js

const nextConfig = {
  serverRuntimeConfig: {
    // Will only be available on the server side
    apiUrl: process.env.NEXT_SERVER_API_URL || 'http://dockerbackend:8000'
  },
  publicRuntimeConfig: {
    // Will be available on both server and client
    apiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'
  }
}

1.单位:@/config/index.ts

import getConfig from 'next/config';

const config = getConfig();

let apiUrl = process.env.NEXT_PUBLIC_API_URL;
if (config) {
  apiUrl = config?.serverRuntimeConfig?.apiUrl
}

export {
  apiUrl
}

1.在需要API URL的位置导入配置文件:

import { apiUrl } from '@/config'

相关问题