我在 Ubuntu 22.04.4 LTS 服务器中部署了 2 个应用程序, 后端 FastAPI 服务和前端 Reactjs 应用程序。 后端在
http://localhost:8000,
上运行,并在 /api/v1
上提供 API
前端运行在 http://localhost:3000
上,可以在本地访问后端 API。
我的目标是从
web.mydomain.com,
访问前端应用程序,让 ReactJS 应用程序到达同一服务器本地提供的 API。
在这种情况下,Nginx 应该充当反向代理。
但是,我的配置有些不正确,当我访问
http://web.mydomain.com
的应用程序时,当前遇到以下错误
Access to XMLHttpRequest at 'http://localhost:8000/api/v1/login/access_token' from origin 'http://web.mydomain.com' has been blocked by CORS policy: The request client is not a secure context and the resource is in more-private address space `local`.
node -v
v18.19.1
npm list
── @emotion/[email protected]
├── @emotion/[email protected]
├── @emotion/[email protected]
├── @material-ui/[email protected]
├── @material-ui/[email protected]
├── @mui/[email protected]
├── @mui/[email protected]
├── @mui/[email protected]
├── @mui/[email protected]
├── @mui/[email protected]
├── @mui/[email protected]
├── @mui/[email protected]
├── @tanstack/[email protected]
├── @testing-library/[email protected]
├── @testing-library/[email protected]
├── @testing-library/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]
Python 3.10.5
nginx -v
nginx version: nginx/1.18.0 (Ubuntu)
我的初始基本配置是
upstream backend {
server localhost:8000;
}
server {
listen 80;
charset utf-8;
server_name web.mydomain.com;
root /var/www/reactjs_frontend/build;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_types text/css text/javascript application/x-javascript application/json;
# backend urls
location ~ ^/(admin|api|media) {
proxy_redirect off;
proxy_pass http://backend;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
# static files
location /static {
alias /var/www/reactjs_frontend/build/static/;
}
# frontend
location / {
try_files $uri $uri/ /index.html;
}
}
应用程序在
http://web.mydomain.com,
加载,但是当我尝试访问后端的 API 时,假设 http://localhost:8000/api/v1/login/access_token
作为填写登录表单的结果,出现以下问题:
Access to XMLHttpRequest at 'http://localhost:8000/api/v1/login/access_token' from origin 'http://web.mydomain.com' has been blocked by CORS policy: The request client is not a secure context and the resource is in more-private address space `local`.
浏览了一些类似的问题后,例如
还有一些,我更改了配置,应用了以下更改,但没有任何运气。问题仍然存在。
这是我当前的配置:
upstream backend {
server localhost:8000;
}
server {
listen *:80;
server_name web.mydomain.com;
root /var/www/reactjs_frontend/build;
index index.html index.htm;
try_files $uri /index.html;
access_log /var/log/nginx/reactjs_access.log;
error_log /var/log/nginx/reactjs_error.log;
location / {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
add_header 'Access-Control-Expose-Headers' 'Access-Control-Allow-Origin';
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Request-Private-Network' 'true';
add_header 'Access-Control-Allow-Private-Networl' 'true';
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
if ($request_method = 'OPTIONS' ) {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'application/json;';
return 204;
}
if ($request_method = 'GET') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'POST') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
proxy_pass_request_headers on;
}
location /api/v1/ {
proxy_pass http://localhost:8000/api/v1/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header authorization $http_authorization;
proxy_pass_request_headers on;
proxy_no_cache $cookie_nocache $arg_nocache$arg_comment;
proxy_no_cache $http_pragma $http_authorization;
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
if ($request_method = 'OPTIONS') {
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, HEAD' always;
add_header 'Access-Control-Allow-Headers' 'authorization, Origin, X-Requested-With, Content-Type, Accept' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, HEAD' always;
add_header 'Access-Control-Allow-Headers' 'authorization, Origin, X-Requested-With, Content-Type, Accept' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
}
if ($request_method = 'GET') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, HEAD' always;
add_header 'Access-Control-Allow-Headers' 'authorization, Origin, X-Requested-With, Content-Type, Accept' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
}
}
}
要添加有关上下文的更多信息,这是由
index.html
生成的
rpm run build
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#1A73E8"/><link rel="apple-touch-icon" sizes="76x76" href="/apple-icon.png"/><link rel="manifest" href="/manifest.json"/><title>MyApp</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900|Roboto+Slab:400,700"/><link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet"/><script src="https://kit.fontawesome.com/42d5adcbca.js" crossorigin="anonymous"></script><script defer="defer" data-site="YOUR_DOMAIN_HERE" src="https://api.nepcha.com/js/nepcha-analytics.js"></script><script defer="defer" src="/static/js/main.13416a3b.js"></script><link href="/static/css/main.be921a39.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
我也尝试过以下很常见的配置
server {
listen 80;
root /var/www/reactjs_frontend/build;
index index.html index.htm index.nginx-debian.html;
server_name web.mydomain.com;
location / {
# serve static frontend first
try_files $uri $uri/ /index.html =404;
}
# location ~*^/(api|posts|products) {
location /api {
if ($request_method = OPTION) {
add_header Access-Control-Allow-Origin web.mydomain.com;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Content-Type text/plain;
add_header Content-Length 0;
return 204;
}
add_header Access-Control-Allow-Origin web.mydomain.com;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
没有任何运气。
我还在reactjs应用程序中添加了以下
http-proxy-middleware
中的webpack.config.js
const {createProxyMiddleware} = require('http-proxy-middleware');
module.exports = {
resolve: {
fallback: { process: require.resolve('process/browser') },
},
plugins: [
new createProxyMiddleware({
target:"http://localhost:8000",
changeOrigin: true,
})
],
};
反向代理接收来自客户端的请求并将其转发到适当的应用程序,但它仅在您实际到达端点时才起作用。在您的情况下,您试图从您的remote前端应用程序访问local端点,这是主要问题。
您的前端和后端托管在同一服务器上,并且您的子域
web.mydomain.com
链接到该服务器。根据您的 nginx 配置,路径 /
为您的前端服务,而 /api/v1/*
为您的后端服务。这称为“基于路径的路由”。当您点击 https://web.mydomain.com/
时,您的反向代理(在本例中为 nginx)知道它必须为前端应用程序提供服务,并提供必要的文件(HTML、CSS、JS 和其他资源)。从现在开始,网络应用程序中发生的所有事情都只发生在您的浏览器上。因此,当您的 Web 应用程序从浏览器中点击 http://localhost:8000/api/v1/
时,它会尝试访问该计算机的本地主机,而不是来自服务器的本地主机。要访问后端,您需要点击https://web.mydomain.com/api/v1/*
。 您收到的错误表明您正在尝试访问默认情况下被大多数浏览器阻止的专用网络资源。您也可以在
here找到类似的问题。 希望这有帮助:)