Приложение весенней загрузки Crud React возвращает 404, когда клиент находится в Docker - PullRequest
0 голосов
/ 07 апреля 2020

Я пытаюсь включить часть React простого приложения CRUD React / Spring-boot в Docker. Работает нормально, когда ни одна из сторон не находится в Docker. Но когда я создаю файл docker из внешнего интерфейса и запускаю его, я получаю начальную страницу входа, но после этого это стандартная страница с ошибкой белого ярлыка с кодом 404.

Сетевая активность показывает, что он пытается позвонить на http://localhost:808/private, что выглядит как перенаправление на страницу ошибки.

Я думаю, что проблема может заключаться в том, что задняя часть также должна быть в контейнере, что является конечным планом. Но я не уверен, что это проблема. Похоже, что приложение в контейнере должно быть в состоянии сделать вызов API снаружи контейнера.

Вот файл nginx .conf:

# auto detects a good number of processes to run
worker_processes auto;

#Provides the configuration file context in which the directives that affect connection processing are specified.
events {
    # Sets the maximum number of simultaneous connections that can be opened by a worker process.
    worker_connections 8000;
    # Tells the worker to accept multiple connections at a time
    multi_accept on;
}


http {
    # what times to include
    include       /etc/nginx/mime.types;
    # what is the default one
    default_type  application/octet-stream;

    # Sets the path, format, and configuration for a buffered log write
    log_format compression '$remote_addr - $remote_user [$time_local] '
        '"$request" $status $upstream_addr '
        '"$http_referer" "$http_user_agent"';

    server {
        # listen on port 80
        listen 80;

        # save logs here
        access_log /var/log/nginx/access.log compression;

        # nginx root directory
        root /var/www;

        # what file to server as index
        index index.html index.htm;

        location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to redirecting to index.html
            try_files $uri $uri/ /index.html;
        }

        # Media: images, icons, video, audio, HTC
        location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
          expires 1M;
          access_log off;
          add_header Cache-Control "public";
        }

        # Javascript and CSS files
        location ~* \.(?:css|js)$ {
            try_files $uri =404;
            expires 1y;
            access_log off;
            add_header Cache-Control "public";
        }

        # Any route containing a file extension (e.g. /devicesfile.js)
        location ~ ^.+\..+$ {
            try_files $uri =404;
        }
    }
}

Редактировать: больше файлов

DockerFile:

#### Stage 1: Build the react application
FROM node:12.4.0-alpine as build

# Configure the main working directory inside the docker image. 
# This is the base directory used in any further RUN, COPY, and ENTRYPOINT 
# commands.
WORKDIR /app

# Copy the package.json as well as the package-lock.json and install 
# the dependencies. This is a separate step so the dependencies 
# will be cached unless changes to one of those two files 
# are made.
COPY package.json package-lock.json ./
RUN yarn

# Copy the main application
COPY . ./

# Arguments
ARG REACT_APP_API_BASE_URL
ENV REACT_APP_API_BASE_URL=${REACT_APP_API_BASE_URL}

# Build the application
RUN yarn build

#### Stage 2: Serve the React application from Nginx 
FROM nginx:1.17.0-alpine

# Copy the react build from Stage 1
COPY --from=build /app/build /var/www

# Copy our custom nginx config
COPY nginx.conf /etc/nginx/nginx.conf

# Expose port 3000 to the Docker host, so we can access it 
# from the outside.
EXPOSE 80

ENTRYPOINT ["nginx","-g","daemon off;"]

Приложение. js

import React, { Component } from 'react';
import './App.css';
import Home from './Home';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import LicenseList from './LicenseList';
import LicenseEdit from './LicenseEdit';
import { CookiesProvider } from 'react-cookie';

class App extends Component {
  render() {
    return (
      <CookiesProvider>
        <Router>
          <Switch>
            <Route path='/' exact={true} component={Home}/>
            <Route path='/licenses' exact={true} component={LicenseList}/>
            <Route path='/licenses/:id' component={LicenseEdit}/>
          </Switch>
        </Router>
      </CookiesProvider>
    )
  }
}

export default App;

Дом. js

import React, { Component } from 'react';
import './App.css';
import AppNavbar from './AppNavbar';
import { Link } from 'react-router-dom';
import { Button, Container } from 'reactstrap';
import { withCookies } from 'react-cookie';

class Home extends Component {
  state = {
    isLoading: true,
    isAuthenticated: false,
    user: undefined
  };

  constructor(props) {
    super(props);
    const {cookies} = props;
    this.state.csrfToken = cookies.get('XSRF-TOKEN');
    this.login = this.login.bind(this);
    this.logout = this.logout.bind(this);
  }

  async componentDidMount() {
    const response = await fetch('/api/user', {credentials: 'include'});
    const body = await response.text();
    if (body === '') {
      this.setState(({isAuthenticated: false}))
    } else {
      this.setState({isAuthenticated: true, user: JSON.parse(body)})
    }
  }

  login() {
    let port = (window.location.port ? ':' + window.location.port : '');
    if (port === ':3000') {
      port = ':8080';
    }
    window.location.href = '//' + window.location.hostname + port + '/private';
  }

  logout() {
    fetch('/api/logout', {method: 'POST', credentials: 'include',
      headers: {'X-XSRF-TOKEN': this.state.csrfToken}}).then(res => res.json())
      .then(response => {
        window.location.href = response.logoutUrl + "?id_token_hint=" +
          response.idToken + "&post_logout_redirect_uri=" + window.location.origin;
      });
  }

  render() {
    const message = this.state.user ?
      <h2>Welcome, {this.state.user.name}!</h2> :
      <p>Please log in to manage Analytics Licenses</p>;

    const button = this.state.isAuthenticated ?
      <div>
        <Button color="link"><Link to="/licenses">Manage Analytics Licenses</Link></Button>
        <br/>
        <Button color="link" onClick={this.logout}>Logout</Button>
      </div> :
      <Button color="primary" onClick={this.login}>Login</Button>;

    return (
      <div>
        <AppNavbar/>
        <Container fluid>
          {message}
          {button}
        </Container>
      </div>
    );
  }
}

export default withCookies(Home);

Любые идеи / мысли приветствуются.

1 Ответ

1 голос
/ 07 апреля 2020

Похоже, у вас nginx работает в контейнере, привязанном к порту 3000 на локальном хосте, а сервер API работает на порту 8080. Поскольку оба работают на разных портах, это похоже на сайты, работающие в разных доменах. Вызов API из приложения реагировать должен содержать полный URL-адрес сервера API. ie, await fetch('/api/user',... недостаточно. Вместо этого оно должно быть await fetch('http://localhost:8080/api/user',....

. Вы можете использовать переменную окружения для переключения хоста API при создании приложения реакции.

const API_HOST = process.env.REACT_APP_API_HOST || '';

class Home extends Component {
...

Тогда ваши последующие вызовы API могут быть выполнены следующим образом:

fetch(API_HOST + '/api/user', ... 

Вам просто нужно установить переменную env REACT_APP_API_HOST в http://localhost:8080 при создании приложения реагирования.

PS : Вам также необходимо использовать ajax требует входа в систему вместо простой замены атрибута href.

...