NGINX 设置以匹配代理中间件配置
NGINX Setup to Match Proxy Middleware Configuration
我有以下 setupProxy.js class 为 api 调用我的服务器配置重定向。
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
"/api/tours",
createProxyMiddleware({
target: "http://localhost:5000",
changeOrigin: true,
})
);
};
我的App.js长得像
const App = () => {
const { userDetails } = useContext(AuthContext);
const { colorMode } = useContext(ColorModeContext);
let currentTheme = React.useMemo(() =>
createTheme(deepmerge(getDesignTokens(colorMode)), getThemedComponents(colorMode)),
[colorMode]
);
currentTheme = responsiveFontSizes(currentTheme);
return (
<ThemeProvider theme={currentTheme}>
<CssBaseline />
<Router>
<Switch>
<AuthRoute exact path="/" component={HomePage} />
<AuthRoute path="/home" component={HomePage} />
<Route path="/public/:id" component={PlayerPage} />
<AuthRoute path="/tours/:id" component={PlayerPage} />
<Route path="/login">
{userDetails == null ? <LoginPage /> : <Redirect to="/home" />}
</Route>
<Route component={FourOhFour} />
</Switch>
</Router>
</ThemeProvider>
);
};
export default App;
我可以使用 url 之类的
导航到我的 PlayerPage
localhost:3000/tours/eef67wsrr899iop009
这加载正常,PlayerPage 看起来像
const PlayerPage = () => {
const history = useHistory();
const { id } = useParams();
const mode = LocalStorgaeCache.getItem(APP_COLOR_MODE_KEY);
const theme = createTheme(deepmerge(getDesignTokens(mode), getThemedComponents(mode)));
const { userDetails } = useContext(AuthContext);
const { tourDetails, isLoading: isLoadingTour, dispatch } = useContext(TourContext);
const [loading, setLoading] = useState(true);
const [showTagInfo, setTagId] = useState(0);
const [tagInfoWindowVisible, showTagInfoWindow] = useState(false);
const [results] = useState([]);
const [setTour] = useState();
const showTagging = useRef(false);
const [showScan, setShowScan] = useState(false);
const [addTag, setAddTag] = useState(false);
const [tagging, setTagging] = useState(false);
const [myPos, setPos] = useState([]);
const myLayer = useRef(0);
const tagEditing = useRef(false);
const refreshTag = useRef(false);
const [myTagNumber, setTagNumber] = useState(0);
const [showPosInfo, setPosInfo] = useState('');
const [snackMessage, setSnackMessage] = useState('');
const [isMobile, setIsMobile] = useState(false);
const [myTags, setTags] = useState([{}]);
const [watermark, setWatermark] = useState();
useEffect(() => {
return () => {
dispatch(clearLoadedTour());
};
}, []);
useEffect(() => {
setIsMobile(navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i));
const actualLoad = async () => {
if (userDetails == null) {
history.push("/login");
}
await getTour(userDetails, id, dispatch);
setLoading(false);
};
if (tourDetails == null) {
actualLoad();
}
else {
const simulateLoad = async () => {
await new Promise((r) => setTimeout(r, 1000));
setLoading(false);
};
simulateLoad();
}
}, [dispatch, history, id, tourDetails, userDetails]);
return (
<ThemeProvider theme={theme}>
<Fragment>
<Backdrop
sx={{ color: "white", zIndex: (theme) => theme.zIndex.drawer + 1 }}
open={loading}>
<CircularProgress color="inherit" />
</Backdrop>
{ tourDetails != null ? (
<div>
{!watermark && <Watermark />}
<SimpleSnackBar snackMessage={snackMessage} />
<InfoCard
tagEditing={tagEditing}
setTagging={setTagging}
setShow={showTagInfoWindow}
refreshTag={refreshTag}
setTour={setTour}
setShowScan={setShowScan}
results={results}
tagNumber={myTagNumber}
tags={myTags}
tour={tourDetails?.MyappTour}
pos={myPos}
setAddTag={setAddTag}
cb={showPosInfo}
st={showTagInfo}
/>
{tagInfoWindowVisible && (
<MediaCard
tagEditing={tagEditing}
tagId={showTagInfo}
setShow={showTagInfoWindow}
/>
)}
<Player
token={tourDetails?.azureServiceSasToken}
tour={tourDetails?.MyappTour}
account={tourDetails?.azureStorageUri}
setSnackMessage={setSnackMessage}
layer={myLayer}
tagging2={tagging}
refreshTag={refreshTag}
setTagId={setTagId}
showTagInfoWindow={showTagInfoWindow}
setPosInfo={setPosInfo}
setLoading={setLoading}
setNewTagPosition={setPos}
tagEditing={tagEditing}
/>
</div>
) : ( <></> ) }
</Fragment>
</ThemeProvider>
);
};
export default PlayerPage;
问题是,当我使用 NGINX 作为反向代理和负载平衡器部署此客户端和服务器时,
myapp.com/tours/eef67wsrr899iop009
不起作用,它只是给出一个空白页面,浏览器控制台 window 正在显示
Uncaught SyntaxError: Unexpected token '<'
Manifest: Line: 1, column: 1, Syntax error.
我的manifest.json文件是
{
"short_name": "Myapp",
"name": "Myapp by vrpm",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
我的index.html是
<!DOCTYPE html>
<html lang="en">
<head>
<title>Myapp</title>
<meta charset="utf-8" />
<meta name="theme-color" content="#000000" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=0, maximum-scale=1, minimum-scale=1"
/>
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
NGINX 配置文件如下所示
worker_processes auto;
events {
worker_connections 1024;
}
pid /var/run/nginx.pid;
http {
include mime.types;
upstream loadbalancer {
server server:5000 weight=3;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
port_in_redirect off;
absolute_redirect off;
return 301 https://$host$request_uri;
}
server {
listen [::]:443 ssl;
listen 443 ssl;
server_name myapp.app* myapp.co* myapp-dev.uksouth.azurecontainer.io* localhost*;
error_page 497 https://$host:$server_port$request_uri;
error_log /var/log/nginx/client-proxy-error.log;
access_log /var/log/nginx/client-proxy-access.log;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 24h;
keepalive_timeout 300;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
ssl_certificate /etc/nginx/certificate.crt;
ssl_certificate_key /etc/nginx/private.key;
root /usr/share/nginx/html;
index index.html index.htm index.nginx-debian.html;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
try_files $uri $uri/ /index.html;
}
location /api/auth {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location /api/tours {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
}
}
在本地,此配置工作正常,没有迹象表明我的 manifest.json 或 index.html 文件有任何问题。所以问题我觉得一定是:
如何修改我的 NGINX 代理以允许使用 url myapp.com/tours/<some-id>
通过客户端直接路由?
编辑。请注意,在我的 AuthRoute 中,我使用以下代码记录请求路径
import { useContext } from "react";
import { AuthContext } from "../context/auth/authContext";
import { Route, Redirect } from "react-router-dom";
const AuthRoute = ({ component: Component, ...rest }) => {
const authContext = useContext(AuthContext);
const { isAuthenticated, isAuthorizing } = authContext;
console.log(`Navigation request for ${window.location.href}`);
return (
<Route
{...rest}
render={props =>
!isAuthenticated && !isAuthorizing ? (<Redirect to="/login" />) : (<Component {...props} />)
}
/>
);
};
export default AuthRoute;
在本地,这会打印出请求的路线并导航到;所以
Navigation request for https://localhost:3000/tours/3r4et66ksop093jsn
在 Azure 上部署时,这些消息永远不会显示,这表明 NGINX 正在干预。
我已经实施了建议的更改,我的 .config 现在看起来像
worker_processes auto;
events {
worker_connections 1024;
}
pid /var/run/nginx.pid;
http {
include mime.types;
upstream loadbalancer {
server server:5000 weight=3;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
port_in_redirect off;
absolute_redirect off;
return 301 https://$host$request_uri;
}
server {
listen [::]:443 ssl;
listen 443 ssl;
server_name viewform.app* viewform.co* viewform-dev.uksouth.azurecontainer.io* localhost*;
error_page 497 https://$host:$server_port$request_uri;
error_log /var/log/nginx/client-proxy-error.log;
access_log /var/log/nginx/client-proxy-access.log;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 24h;
keepalive_timeout 300;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
ssl_certificate /etc/nginx/certificate.crt;
ssl_certificate_key /etc/nginx/private.key;
root /usr/share/nginx/html;
index index.html index.htm index.nginx-debian.html;
location /api/auth {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location /api/tours {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location / {
try_files $uri /index.html;
}
}
}
现在当我导航到 dev.myapp/public/tours/ 我得到一个空白页面,如下所示
带有以下警告
Uncaught SyntaxError: Unexpected token '<'
manifest.json:1 Manifest: Line: 1, column: 1, Syntax error.
我的index.html和manifest.json在上面
因为 nginx 不知道由 react-router
处理的 tours
路径你可以告诉 nginx 将所有请求重新路由到 /
根路由然后传递请求到 index.html
或者您可以添加正则表达式路径并将所有请求路由到 nginx.conf
中的 /
根位置。由于现在 /
根位置正在处理所有其他请求,因此可能不会传递到其他位置,因此最好将当前路由移动到 nginx.conf
.
中的静态位置下方
下面是如何将所有请求路由到 index.html
文件
nginx.conf
...
location /api/auth {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location /api/tours {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location / {
try_files $uri /index.html; # change as below
}
...
OP 编辑:在我的package.json“主页”:“。”中,需要是“主页”:“/”。这就是导致路由失败的原因 - 偷偷摸摸的。希望这对其他人有帮助。
我有以下 setupProxy.js class 为 api 调用我的服务器配置重定向。
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
"/api/tours",
createProxyMiddleware({
target: "http://localhost:5000",
changeOrigin: true,
})
);
};
我的App.js长得像
const App = () => {
const { userDetails } = useContext(AuthContext);
const { colorMode } = useContext(ColorModeContext);
let currentTheme = React.useMemo(() =>
createTheme(deepmerge(getDesignTokens(colorMode)), getThemedComponents(colorMode)),
[colorMode]
);
currentTheme = responsiveFontSizes(currentTheme);
return (
<ThemeProvider theme={currentTheme}>
<CssBaseline />
<Router>
<Switch>
<AuthRoute exact path="/" component={HomePage} />
<AuthRoute path="/home" component={HomePage} />
<Route path="/public/:id" component={PlayerPage} />
<AuthRoute path="/tours/:id" component={PlayerPage} />
<Route path="/login">
{userDetails == null ? <LoginPage /> : <Redirect to="/home" />}
</Route>
<Route component={FourOhFour} />
</Switch>
</Router>
</ThemeProvider>
);
};
export default App;
我可以使用 url 之类的
导航到我的PlayerPage
localhost:3000/tours/eef67wsrr899iop009
这加载正常,PlayerPage 看起来像
const PlayerPage = () => {
const history = useHistory();
const { id } = useParams();
const mode = LocalStorgaeCache.getItem(APP_COLOR_MODE_KEY);
const theme = createTheme(deepmerge(getDesignTokens(mode), getThemedComponents(mode)));
const { userDetails } = useContext(AuthContext);
const { tourDetails, isLoading: isLoadingTour, dispatch } = useContext(TourContext);
const [loading, setLoading] = useState(true);
const [showTagInfo, setTagId] = useState(0);
const [tagInfoWindowVisible, showTagInfoWindow] = useState(false);
const [results] = useState([]);
const [setTour] = useState();
const showTagging = useRef(false);
const [showScan, setShowScan] = useState(false);
const [addTag, setAddTag] = useState(false);
const [tagging, setTagging] = useState(false);
const [myPos, setPos] = useState([]);
const myLayer = useRef(0);
const tagEditing = useRef(false);
const refreshTag = useRef(false);
const [myTagNumber, setTagNumber] = useState(0);
const [showPosInfo, setPosInfo] = useState('');
const [snackMessage, setSnackMessage] = useState('');
const [isMobile, setIsMobile] = useState(false);
const [myTags, setTags] = useState([{}]);
const [watermark, setWatermark] = useState();
useEffect(() => {
return () => {
dispatch(clearLoadedTour());
};
}, []);
useEffect(() => {
setIsMobile(navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i));
const actualLoad = async () => {
if (userDetails == null) {
history.push("/login");
}
await getTour(userDetails, id, dispatch);
setLoading(false);
};
if (tourDetails == null) {
actualLoad();
}
else {
const simulateLoad = async () => {
await new Promise((r) => setTimeout(r, 1000));
setLoading(false);
};
simulateLoad();
}
}, [dispatch, history, id, tourDetails, userDetails]);
return (
<ThemeProvider theme={theme}>
<Fragment>
<Backdrop
sx={{ color: "white", zIndex: (theme) => theme.zIndex.drawer + 1 }}
open={loading}>
<CircularProgress color="inherit" />
</Backdrop>
{ tourDetails != null ? (
<div>
{!watermark && <Watermark />}
<SimpleSnackBar snackMessage={snackMessage} />
<InfoCard
tagEditing={tagEditing}
setTagging={setTagging}
setShow={showTagInfoWindow}
refreshTag={refreshTag}
setTour={setTour}
setShowScan={setShowScan}
results={results}
tagNumber={myTagNumber}
tags={myTags}
tour={tourDetails?.MyappTour}
pos={myPos}
setAddTag={setAddTag}
cb={showPosInfo}
st={showTagInfo}
/>
{tagInfoWindowVisible && (
<MediaCard
tagEditing={tagEditing}
tagId={showTagInfo}
setShow={showTagInfoWindow}
/>
)}
<Player
token={tourDetails?.azureServiceSasToken}
tour={tourDetails?.MyappTour}
account={tourDetails?.azureStorageUri}
setSnackMessage={setSnackMessage}
layer={myLayer}
tagging2={tagging}
refreshTag={refreshTag}
setTagId={setTagId}
showTagInfoWindow={showTagInfoWindow}
setPosInfo={setPosInfo}
setLoading={setLoading}
setNewTagPosition={setPos}
tagEditing={tagEditing}
/>
</div>
) : ( <></> ) }
</Fragment>
</ThemeProvider>
);
};
export default PlayerPage;
问题是,当我使用 NGINX 作为反向代理和负载平衡器部署此客户端和服务器时,
myapp.com/tours/eef67wsrr899iop009
不起作用,它只是给出一个空白页面,浏览器控制台 window 正在显示
Uncaught SyntaxError: Unexpected token '<' Manifest: Line: 1, column: 1, Syntax error.
我的manifest.json文件是
{
"short_name": "Myapp",
"name": "Myapp by vrpm",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
我的index.html是
<!DOCTYPE html>
<html lang="en">
<head>
<title>Myapp</title>
<meta charset="utf-8" />
<meta name="theme-color" content="#000000" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=0, maximum-scale=1, minimum-scale=1"
/>
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
NGINX 配置文件如下所示
worker_processes auto;
events {
worker_connections 1024;
}
pid /var/run/nginx.pid;
http {
include mime.types;
upstream loadbalancer {
server server:5000 weight=3;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
port_in_redirect off;
absolute_redirect off;
return 301 https://$host$request_uri;
}
server {
listen [::]:443 ssl;
listen 443 ssl;
server_name myapp.app* myapp.co* myapp-dev.uksouth.azurecontainer.io* localhost*;
error_page 497 https://$host:$server_port$request_uri;
error_log /var/log/nginx/client-proxy-error.log;
access_log /var/log/nginx/client-proxy-access.log;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 24h;
keepalive_timeout 300;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
ssl_certificate /etc/nginx/certificate.crt;
ssl_certificate_key /etc/nginx/private.key;
root /usr/share/nginx/html;
index index.html index.htm index.nginx-debian.html;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
try_files $uri $uri/ /index.html;
}
location /api/auth {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location /api/tours {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
}
}
在本地,此配置工作正常,没有迹象表明我的 manifest.json 或 index.html 文件有任何问题。所以问题我觉得一定是:
如何修改我的 NGINX 代理以允许使用 url myapp.com/tours/<some-id>
通过客户端直接路由?
编辑。请注意,在我的 AuthRoute 中,我使用以下代码记录请求路径
import { useContext } from "react";
import { AuthContext } from "../context/auth/authContext";
import { Route, Redirect } from "react-router-dom";
const AuthRoute = ({ component: Component, ...rest }) => {
const authContext = useContext(AuthContext);
const { isAuthenticated, isAuthorizing } = authContext;
console.log(`Navigation request for ${window.location.href}`);
return (
<Route
{...rest}
render={props =>
!isAuthenticated && !isAuthorizing ? (<Redirect to="/login" />) : (<Component {...props} />)
}
/>
);
};
export default AuthRoute;
在本地,这会打印出请求的路线并导航到;所以
Navigation request for https://localhost:3000/tours/3r4et66ksop093jsn
在 Azure 上部署时,这些消息永远不会显示,这表明 NGINX 正在干预。
我已经实施了建议的更改,我的 .config 现在看起来像
worker_processes auto;
events {
worker_connections 1024;
}
pid /var/run/nginx.pid;
http {
include mime.types;
upstream loadbalancer {
server server:5000 weight=3;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
port_in_redirect off;
absolute_redirect off;
return 301 https://$host$request_uri;
}
server {
listen [::]:443 ssl;
listen 443 ssl;
server_name viewform.app* viewform.co* viewform-dev.uksouth.azurecontainer.io* localhost*;
error_page 497 https://$host:$server_port$request_uri;
error_log /var/log/nginx/client-proxy-error.log;
access_log /var/log/nginx/client-proxy-access.log;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 24h;
keepalive_timeout 300;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
ssl_certificate /etc/nginx/certificate.crt;
ssl_certificate_key /etc/nginx/private.key;
root /usr/share/nginx/html;
index index.html index.htm index.nginx-debian.html;
location /api/auth {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location /api/tours {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location / {
try_files $uri /index.html;
}
}
}
现在当我导航到 dev.myapp/public/tours/ 我得到一个空白页面,如下所示
带有以下警告
Uncaught SyntaxError: Unexpected token '<' manifest.json:1 Manifest: Line: 1, column: 1, Syntax error.
我的index.html和manifest.json在上面
因为 nginx 不知道由 react-router
处理的 tours
路径你可以告诉 nginx 将所有请求重新路由到 /
根路由然后传递请求到 index.html
或者您可以添加正则表达式路径并将所有请求路由到 nginx.conf
中的 /
根位置。由于现在 /
根位置正在处理所有其他请求,因此可能不会传递到其他位置,因此最好将当前路由移动到 nginx.conf
.
下面是如何将所有请求路由到 index.html
文件
nginx.conf
...
location /api/auth {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location /api/tours {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://loadbalancer;
}
location / {
try_files $uri /index.html; # change as below
}
...
OP 编辑:在我的package.json“主页”:“。”中,需要是“主页”:“/”。这就是导致路由失败的原因 - 偷偷摸摸的。希望这对其他人有帮助。