Next.js getServerSideProps 无法使用 docker

Next.js getServerSideProps is not working using docker

目前我正在尝试通过Next.js通过SSR与后端服务器通信后获取数据并撒在页面上。

但是,一个问题是,当我在本地 运行 npm run dev 时,getServerSideProps 运行 很好,但是当我通过 Docker-compose 上传到容器时,我的 getServerSideProps API 不起作用。

    const ResultMenu: NextPage<Props> = ({ CategoryData }) => {  
     ...
    };
    
    export default ResultMenu;
    
    export const getServerSideProps: GetServerSideProps = async (context) => {
      try {
        const { menuId } = context.query;
        const response = await axios.get<CategoryType[]>(
          "http://localhost:8080/category/get/menu",
          {
            headers: {
              "Content-Type": "application/json",
              "Access-Control-Allow-Origin": "*",
            },
            params: {
              menuId: menuId,
            },
          }
        );
        const data = response.data;
        console.log(data);
        return {
          props: {
            CategoryData: data,
          },
        };
      } catch (err) {
        console.log(err);
        return {
          props: {},
        };
      }
    };

在前端容器中,出现这个错误码

Error: connect ECONNREFUSED 127.0.0.1:8080

    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1195:16) {

  errno: -111,

  code: 'ECONNREFUSED',

  syscall: 'connect',

  address: '127.0.0.1',

  port: 8080,

  config: {

    transitional: {

      silentJSONParsing: true,

      forcedJSONParsing: true,

      clarifyTimeoutError: false

    },

    adapter: [Function: httpAdapter],

    transformRequest: [ [Function: transformRequest] ],

    transformResponse: [ [Function: transformResponse] ],

    timeout: 0,

    xsrfCookieName: 'XSRF-TOKEN',

    xsrfHeaderName: 'X-XSRF-TOKEN',

    maxContentLength: -1,

    maxBodyLength: -1,

    validateStatus: [Function: validateStatus],

    headers: {

      Accept: 'application/json, text/plain, */*',

      'Content-Type': 'application/json',

      'Access-Control-Allow-Origin': '*',

      'User-Agent': 'axios/0.26.1'

    },

    params: { menuId: '1' },

    method: 'get',

    url: 'http://localhost:8080/category/get/menu',

    data: undefined

  },

  request: <ref *1> Writable {

    _writableState: WritableState {

      objectMode: false,

      highWaterMark: 16384,

      finalCalled: false,

      needDrain: false,

      ending: false,

      ended: false,

      finished: false,

      destroyed: false,

      decodeStrings: true,

      defaultEncoding: 'utf8',

      length: 0,

      writing: false,

      corked: 0,

      sync: true,

      bufferProcessing: false,

      onwrite: [Function: bound onwrite],

      writecb: null,

      writelen: 0,

      afterWriteTickInfo: null,

      buffered: [],

      bufferedIndex: 0,

      allBuffers: true,

      allNoop: true,

      pendingcb: 0,

      constructed: true,

      prefinished: false,

      errorEmitted: false,

      emitClose: true,

      autoDestroy: true,

      errored: null,

      closed: false,

      closeEmitted: false,

      [Symbol(kOnFinished)]: []

    },

    _events: [Object: null prototype] {

      response: [Function: handleResponse],

      error: [Function: handleRequestError],

      socket: [Function: handleRequestSocket]

    },

    _eventsCount: 3,

    _maxListeners: undefined,

    _options: {

      maxRedirects: 21,

      maxBodyLength: 10485760,

      protocol: 'http:',

      path: '/category/get/menu?menuId=1',

      method: 'GET',

      headers: [Object],

      agent: undefined,

      agents: [Object],

      auth: undefined,

      hostname: 'localhost',

      port: '8080',

      nativeProtocols: [Object],

      pathname: '/category/get/menu',

      search: '?menuId=1'

    },

    _ended: true,

    _ending: true,

    _redirectCount: 0,

    _redirects: [],

    _requestBodyLength: 0,

    _requestBodyBuffers: [],

    _onNativeResponse: [Function (anonymous)],

    _currentRequest: ClientRequest {

      _events: [Object: null prototype],

      _eventsCount: 7,

      _maxListeners: undefined,

      outputData: [],

      outputSize: 0,

      writable: true,

      destroyed: false,

      _last: true,

      chunkedEncoding: false,

      shouldKeepAlive: false,

      maxRequestsOnConnectionReached: false,

      _defaultKeepAlive: true,

      useChunkedEncodingByDefault: false,

      sendDate: false,

      _removedConnection: false,

      _removedContLen: false,

      _removedTE: false,

      _contentLength: 0,

      _hasBody: true,

      _trailer: '',

      finished: true,

      _headerSent: true,

      _closed: false,

      socket: [Socket],

      _header: 'GET /category/get/menu?menuId=1 HTTP/1.1\r\n' +

        'Accept: application/json, text/plain, */*\r\n' +

        'Content-Type: application/json\r\n' +

        'Access-Control-Allow-Origin: *\r\n' +

        'User-Agent: axios/0.26.1\r\n' +

        'Host: localhost:8080\r\n' +

        'Connection: close\r\n' +

        '\r\n',

      _keepAliveTimeout: 0,

      _onPendingData: [Function: nop],

      agent: [Agent],

      socketPath: undefined,

      method: 'GET',

      maxHeaderSize: undefined,

      insecureHTTPParser: undefined,

      path: '/category/get/menu?menuId=1',

      _ended: false,

      res: null,

      aborted: false,

      timeoutCb: null,

      upgradeOrConnect: false,

      parser: null,

      maxHeadersCount: null,

      reusedSocket: false,

      host: 'localhost',

      protocol: 'http:',

      _redirectable: [Circular *1],

      [Symbol(kCapture)]: false,

      [Symbol(kNeedDrain)]: false,

      [Symbol(corked)]: 0,

      [Symbol(kOutHeaders)]: [Object: null prototype]

    },

    _currentUrl: 'http://localhost:8080/category/get/menu?menuId=1',

    [Symbol(kCapture)]: false

  },

  response: undefined,

  isAxiosError: true,

  toJSON: [Function: toJSON]

}

1

undefined

Docker文件

FROM node:12

ENV PORT 3000

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Installing dependencies
COPY package*.json /usr/src/app/
RUN npm install

# Copying source files
COPY . /usr/src/app

# Building app
RUN npm run build
EXPOSE 3000

# Running the app
CMD "npm" "run" "dev"

docker-compose.yml

version: "3"

services:
  frontend:
    container_name: frontend
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/usr/src/app
      - /usr/src/app/node_modules
      - /usr/src/app/.next
    networks:
      - network-tier
      
  backend:
    container_name: backend
    build: ./backend
    depends_on:
      - mysqldb
    ports:
      - 8080:8080
    environment:
      spring.datasource.url: "jdbc:mysql://mysqldb:3306/test_db?useSSL=false&useLegacyDatetimeCode=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul&characterEncoding=UTF-8&autoReconnect=true&createDatabaseIfNotExist=true"
    volumes:
      - ./menu-canvas:/usr/src/backend
    networks:
      - network-tier
    tty: true

  mysqldb:
    image: mysql:5.7
    container_name: mysqldb
    environment:
      MYSQL_DATABASE: test_db
      MYSQL_ROOT_PASSWORD: "0000"
      MYSQL_ROOT_HOST: "%"
      CHARACTER_SET_SERVER: utf8
    command:
      [
        "--character-set-server=utf8mb4",
        "--collation-server=utf8mb4_unicode_ci",
      ]
    volumes:
      - ./menu-canvas:/usr/src/db
    ports:
      - "3306:3306"

    networks:
      - network-tier
    platform: linux/amd64

networks:
  network-tier:
    external: true

volumes:
  menu-canvas:

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    domains: ["localhost", "*"],
  },
  reactStrictMode: true,
};

module.exports = nextConfig;

package.json

{
  "name": "frontend",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
 ...
  },
  "devDependencies": {
 ...
  },
  "proxy": {
    "*": {
      "target": "http://localhost:8080"
    }
  }
}

整天想了很多,就是不知道怎么...求救!

当 运行 连接 getServerSideProps 时,通信将是容器到容器。因此,对于这些请求,到 localhost 的路由将不起作用。相反,它需要类似于 backend:8080(当从 frontend 服务与 backend 服务通信时)。

假设您按预期公开所有端口,localhost 域将在客户端请求上按预期工作。

当您 运行 没有 docker 时一切正常,因为所有服务都在 localhost 上。当 运行 通过 docker-compose 它们不再是。

如果您真的想使用 localhost 而不是服务名称,您可以使用 network host https://docs.docker.com/network/host/