简体   繁体   中英

Proxying API Requests in Docker Container running react app

I'm running a simple react app in a docker container. During development I'm using the proxy key in package.json to specify my backend api url: "proxy": "http://localhost:5000"

Everything works fine when I run npm start locally. However, when I npm start inside a docker container it's pointing to "http://localhost:3000" . I'm tried setting the proxy manually as well, as demonstrated by my Dockerfile below, but nothing seems to work:

FROM node:13-alpine
WORKDIR /app

# install dependencies
COPY package*.json ./
RUN npm install --silent

# copy source code
COPY src/ ./src/
COPY public/ ./public/

RUN npm config set proxy http://localhost:5000  # set manully
CMD ["npm", "start"]

Am I doing something wrong or is this not possible?

You need to set the port to your backend service instead of localhost while running the app in docker. Check the following docker container and it's services for example. We have the frontend running in port 3000 and backend running in port 5000 . So, replace localhost with "proxy": "http://backend:5000"

version: '3'

services:
  backend:
    build: ./backend
    ports:
      - 5000:5000
  frontend:
    build: ./frontend
    ports:
      - 3000:3000
    links:
      - backend
    command: npm start

"proxy": "http://localhost:5000" works perfectly fine in the development stage, because the webpack DevServer handles proxying by itself. Once you deploy your React application, it stops operating. I have experienced the same problem when trying to make my containerized React application talk to the containerized API. I was using Nginx as a web server to serve the React application. I followed this guide to integrate Nginx with a Docker container. This is how the nginx.conf initially looked like:

server {

  listen 80;

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  error_page   500 502 503 504  /50x.html;

  location = /50x.html {
    root   /usr/share/nginx/html;
  }

}

but after I made a few tweaks here and there, I came up with this configuration (I am going to talk what api stands for in a bit):

server {

  listen 80;

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  location /api {
    resolver 127.0.0.11;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://api:8000;
  }

  error_page   500 502 503 504  /50x.html;

  location = /50x.html {
    root   /usr/share/nginx/html;
  }

}

What has changed? I added a root location for the API endpoints, since all of them have a common prefix /api . The proxy_pass property lets us proxy all the request coming to the /api to our backend that is exposed via port 8000. api is a just a name of the container defined in the docker-compose.yaml .

For the reference, this is my React app's Dockerfile :

# build environment
FROM node:15.2.1 as build
WORKDIR /app
COPY ./client ./
RUN yarn
RUN yarn build

# production environment
FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY --from=build /app/nginx/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

and the most important file ( docker-compose.yaml ):

version: "3.8"

services:
  client:
    build:
      context: .
      dockerfile: client/Dockerfile
    container_name: $CLIENT_CONTAINER_NAME
    restart: unless-stopped
    env_file: .env
    ports:
      - "1337:80"
    networks:
      - my-network
    links:
      - api
  api:
    build:
      context: .
      dockerfile: server/Dockerfile
    container_name: $API_CONTAINER_NAME
    restart: unless-stopped
    env_file: .env
    ports:
      - "8000:8000"
    networks:
      - my-network
    links:
      - mongo
  mongo:
    image: mongo
    container_name: $DB_CONTAINER_NAME
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_INITDB_ROOT_USERNAME=$MONGO_INITDB_ROOT_USERNAME
      - MONGO_INITDB_ROOT_PASSWORD=$MONGO_INITDB_ROOT_PASSWORD
      - DB_NAME=$DB_NAME
      - MONGO_HOSTNAME=$MONGO_HOSTNAME
    volumes:
      - ~/data/db:/data/db
    ports:
      - 27017:27017
    networks:
      - my-network

networks:
  my-network:
    driver: bridge

You're now running your React app inside a Docker container, so your "localhost" is no longer your local machine, but the container instead. You need to proxy-it to your backend's IP. Are you running the API in another container?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM