reactjs - 当客户端在 Docker 中时,Crud React spring-boot 应用程序返回 404
问题描述
我正在尝试将一个简单的 CRUD React/Spring-boot 应用程序的 React 部分包含到 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;
}
}
}
编辑:更多文件
Docker文件:
#### 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);
任何想法/想法都是最受欢迎的。
解决方案
看起来您已经nginx
在绑定到3000
localhost 中端口的容器中运行,并且 API 服务器正在端口上运行8080
。由于两者都在不同的端口上运行,因此类似于在不同域中运行的网站。从 react app 发出的 api 调用应该包含 api 服务器的完整 url。即,await fetch('/api/user',...
还不够。它应该是await fetch('http://localhost:8080/api/user',...
.
您可以在构建 React 应用程序时使用环境变量来切换 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
属性。
推荐阅读
- r - R 相当于 Stata 权重
- c++ - CPP 中类似控制台的应用程序
- arrays - Postgresql:替换单个字段值中的所有单词
- javascript - 使用 Express 获得一个空的身体
- amazon-elb - 将负载均衡器配置为广播器
- flutter - 在移动设备中实现 Flutter Web 的菜单
- apache-spark - Apache Spark:Cassandra 阅读:如何在写入文件时忽略或替换 '\n' 字符
- php - 使用 $_REQUEST 通过 AJAX 将数据提交到 url
- python - 如何找到最近几何的索引
- typo3 - 如何将新闻中的 showPrevNext 限制为类别?