如何使用 Nginx 反向代理正确处理相对 URL

如何使用 Nginx 反向代理正确处理相对 URL

当然,我不是第一个尝试example.com从提供域名服务的人example.net/bbb,但我还没有找到解决方案。

我的 NGINX 配置如下指导方针看起来像这样:

server {
    listen 80;
    server_name example.net;
    root /path/to/aaa;

    location /bbb/ {
        proxy_pass http://example.com/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location / {
        try_files $uri $uri/ /index.html;
    }
    location ~ \.(svg|ttf|js|css|svgz|eot|otf|woff|jpg|jpeg|gif|png|ico)$ {
        access_log off;
        log_not_found off;
        expires max;
    }
}

我可以设法渲染的根,example.com但是example.net/bbb

第 1 期

example.net/bbb/some/path无法按预期工作,并且index.html呈现example.net了。

第 2 期

example.com/assets由于浏览器搜索,中的任何资产都会给出 404example.net/assets错误。如果我能解决这个问题而不用到处都放置绝对路径,那就太好了。

答案1

问题基本上是使用proxy_pass指令不会重写 HTML 代码,因此相对 URL(例如 )img src="/assets/image.png"不会神奇地改变为img src="/bbb/assets/image.png"

我写了一篇关于在 Apache httpd 中解决这个问题的潜在策略这里对于 Nginx 来说也有类似的解决方案:

  • 如果你能控制example.com应用程序/内容的部署方式,部署在同一个基本 URI 中您想在 example.net 上使用反向代理
    --> 部署您的代码 example.com/bbb,然后您的操作proxy_pass将变得相当容易,因为 /assets/image.png 将被移动到 /bbb/assets/image.png:

      location /bbb/ {
           proxy_pass http://example.com/bbb/; 
    
  • 如果您可以控制example.com应用程序/内容的部署方式:
    更改为相对路径即,而不是img src="/assets/image.png"
    引用img src="./assets/image.png"来自页面example.com/index.html
    img src="../../assets/image.png"来自页面example.com/some/path/index.html

  • 也许你很幸运,example.com 只使用根目录中的一些 URI 路径并且 example.net 都没有使用上述任何一项,那么只需反向代理每个必要的子目录

      location /bbb/ {
           proxy_pass http://example.com/; 
      }
      location /assets/ {
           proxy_pass http://example.com/assets/; 
      }
      location /styles/ {
           proxy_pass http://example.com/styles/; 
    
  • 放弃使用 example.com 作为 example.net 上的子目录,而是将其托管在example.net 的子域名

      server { 
        server_name bbb.example.net 
        location / {
           proxy_pass http://example.com/; 
        }
      }
    
  • 重写(HTML)内容通过启用 nginxngx_http_sub_module。这还允许您使用类似以下内容重写绝对 URL:

      location /bbb/ {
           sub_filter 'src="/assets/'  'src="/bbb/assets/';
           sub_filter 'src="http://example.com/js/' 'src="http://www.example.net/bbb/js/' ;
           sub_filter_once off;
           proxy_pass http://example.com/; 
      }
    

后期添加

  • 有时,开发人员会专门为应用程序位于反向代理或 CDN 后面的部署提供特殊的应用程序设置。然后可以将应用程序配置为生成自引用 URL,其中包含用户正在/应该使用的协议、站点名称和 URI 路径,而不是然后是主机名、协议和/或应用程序检测到的 URIexternal URL。期待像、 这样的术语site URL。那么您不需要在 nginx 中解决任何问题。

答案2

我发现索引页无法正确跳转到子文件夹的原因就像\bbbhtml 文件中的这一行:<base href="/">,这意味着每当跳转到新路径时它都会抛弃任何现有文件夹。

答案3

如果您想要将子目录的 html 文件设为默认的 index.html。例如,将 /main/mainView.html 复制到 /index.html,并使用 index.html 中的 base 标签来设置相对位置的基本路径。

*我认为调整客户端页面相对位置的基本路径不能通过服务器端进行修改,而可以通过客户端(浏览器)进行修改。因为页面(客户端资产)无法知道其在服务器端的真实位置。

答案4

由于主页已将您重定向到路径“/admin/”,因此正确的方法是检查路径并发出“return 302”以调整原始 URL 中显示的“location”。请参阅下面的示例。

Nginx 版本

Docker: nginx:1.25-alpine3.18
Nginx: 1.25

原始网址:

http://192.168.29.2:8088/admin/

反向代理:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name ~^(dns).youdomain.com;

    client_max_body_size 50M;
    include ssl_config.config;

    location = / {
        return 302 https://$host/admin/;
    }

    location /admin/ {
        proxy_pass http://192.168.29.2:8088/admin/;
        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;
    }
}

ssl_配置.config

    # SSL configuration
    ssl_certificate         /etc/nginx/certs/certificate.crt;
    ssl_certificate_key     /etc/nginx/certs/certificate.key;

    #ssl_protocols TLSv1.3 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver_timeout 5s;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";

    ssl_dhparam /etc/nginx/certs/dhparam.pem;

    # Your server DNS here
    resolver 192.168.29.2;

相关内容