URL 中没有尾部斜杠会导致 nginx 尝试从错误位置加载 js

URL 中没有尾部斜杠会导致 nginx 尝试从错误位置加载 js

我有一个类似于所见的 nginx api 网关配置设置这里。该应用程序在“www.foo.com/bar/app/”上提供服务,但我们还希望用户能够访问该网站而不包括尾部斜杠。

目前,当我访问没有尾部斜杠的 URL 时,服务器会抛出 500 错误。深入研究日志显示以下内容:

2021/01/05 22:43:39 [notice] 22#22: *4 rewritten data: "/", args: "", client: 172.29.0.1, server: , request: "GET /bar/app HTTP/1.1", host: "localhost:8080"
2021/01/05 22:43:39 [error] 22#22: *4 open() "/etc/nginx/html/nap/js/compiled/app.js" failed (2: No such file or directory), client: 172.29.0.1, server: , request: "GET /bar/js/compiled/app.js HTTP/1.1", host: "localhost:8080", referrer: "http://localhost:8080/bar/app"

然而,当 URL 带有尾部斜杠时,日志将显示以下序列:

2021/01/05 22:33:55 [notice] 22#22: *1 rewritten data: "//", args: "", client: 172.29.0.1, server: , request: "GET /bar/app/ HTTP/1.1", host: "localhost:8080"
2021/01/05 22:33:55 [notice] 22#22: *1 "^/bar/app(.*)$" matches "/bar/app/js/compiled/app.js", client: 172.29.0.1, server: , request: "GET /bar/app/js/compiled/app.js HTTP/1.1", host: "localhost:8080", referrer: "http://localhost:8080/bar/app/"

目前的API定义+策略:

location /bar/app {
    set $upstream bar_frontend_app_main;
    rewrite ^/bar/app(.*)$ /_bar_frontend_app_service$1 last;
}

location /_bar_frontend_app_service {
    internal;
    set $api_name "Frontend API";

    rewrite ^/_bar_frontend_app_service(.*)$ /$1 break; 
    proxy_pass http://$upstream;      # Proxy the rewritten URI
}

完整配置如下:

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    # Added to troubleshoot trailing slash frontend issue
    log_format upstream_logging '[$time_local] $remote_addr - $remote_user - $server_name to: '
                                '$upstream: $request upstream_response_time $upstream_response_time '
                                'msec $msec request_time $request_time';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    include /etc/nginx/api_gateway.conf; # All API gateway configuration
    include /etc/nginx/conf.d/*.conf;    # Regular web traffic
}

# configuration file /etc/nginx/mime.types:

types {
    ...
}

# configuration file /etc/nginx/api_gateway.conf:
log_format api_main '$remote_addr - $remote_user [$time_local] "$request"'
                    '$status $body_bytes_sent "$http_referer" "$http_user_agent"'
                    '"$http_x_forwarded_for" "$api_name"';

include api_backends.conf;

server {
    set $api_name -; # Start with an undefined API name, each API will update this value
    access_log /var/log/nginx/api_access.log api_main; # Each API may also log to a separate file

    listen 80;

    # API definitions, one per file
    include api_conf.d/*.conf;

    # Error responses
    error_page 404 = @400;         # Invalid paths are treated as bad requests
    proxy_intercept_errors on;     # Do not send backend errors to the client
    include api_json_errors.conf;  # API client friendly JSON error responses
    default_type application/json; # If no content-type then assume JSON

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    rewrite_log on; 
}


# configuration file /etc/nginx/api_backends.conf:

upstream foo_api_main {
    keepalive 32;
    zone foo_service 64k;
    server foo-server:5000;
}

upstream foobar_api_main {
    keepalive 32;
    zone foobar_service 64k;
    server foobar:5000;
}

upstream bar_frontend_app_main {
    keepalive 32;
    zone bar_frontend_app_service 64k;
    server bar-frontend:80;
}

# configuration file /etc/nginx/api_conf.d/foo_api.conf:
# API definition
#

location /api/hello/foo {
   set $upstream foo_api_main;
   rewrite ^/api/hello/foo/(.*)$ /_foo_service$1 last;
}

# This is used when app is running through MAF
location /hello/foo {
   set $upstream foo_api_main;
   rewrite ^/hello/foo/(.*)$ /_foo_service$1 last;
}


# Policy section
#
location /_foo_service {
    internal;
    set $api_name "foo backend API";

    rewrite ^/_foo_service(.*)$ /api/$1 break; # Remove /_foo_service prefix
    proxy_pass http://$upstream;      # Proxy the rewritten URI
}


# configuration file /etc/nginx/api_conf.d/bar_frontend.conf:

location /bar/app {
    set $upstream bar_frontend_app_main;
    rewrite ^/bar/app(.*)$ /_bar_frontend_app_service$1 last;
}

# Policy section
#
location /_bar_frontend_app_service {
    internal;
    set $api_name "Frontend API";

    rewrite ^/_bar_frontend_app_service(.*)$ /$1 break; 
    proxy_pass http://$upstream;      # Proxy the rewritten URI
}


# configuration file /etc/nginx/api_conf.d/foobar_api.conf:
# API definition
#
location /api/hello/foobar {
    set $upstream foobar_api_main;
    rewrite ^/api/hello/foobar/(.*)$ /_foobar_service$1 last;
}

# This is used when app is running through MAF
location /hello/foobar {
   set $upstream foobar_api_main;
   rewrite ^/hello/foobar/(.*)$ /_foobar_service$1 last;
}


# Policy section
location /_foobar_service {
    internal;
    set $api_name "foobar backend API";

    rewrite ^/_foobar_service(.*)$ /$1 break; # Remove /_foobar_service prefix
    proxy_pass http://$upstream;      # Proxy the rewritten URI
}


# configuration file /etc/nginx/api_json_errors.conf:
error_page 400 = @400;
location @400 { return 400 '{"status":400,"message":"Bad request"}\n'; }

error_page 401 = @401;
location @401 { return 401 '{"status":401,"message":"Unauthorized"}\n'; }

error_page 403 = @403;
location @403 { return 403 '{"status":403,"message":"Forbidden"}\n'; }

error_page 404 = @404;
location @404 { return 404 '{"status":404,"message":"Resource not found"}\n'; }

error_page 405 = @405;
location @405 { return 405 '{"status":405,"message":"Method not allowed"}\n'; }

error_page 408 = @408;
location @408 { return 408 '{"status":408,"message":"Request timeout"}\n'; }

error_page 413 = @413;
location @413 { return 413 '{"status":413,"message":"Payload too large"}\n'; }

error_page 414 = @414;
location @414 { return 414 '{"status":414,"message":"Request URI too large"}\n'; }

error_page 415 = @415;
location @415 { return 415 '{"status":415,"message":"Unsupported media type"}\n'; }

error_page 426 = @426;
location @426 { return 426 '{"status":426,"message":"HTTP request was sent to HTTPS port"}\n'; }

error_page 429 = @429;
location @429 { return 429 '{"status":429,"message":"API rate limit exceeded"}\n'; }

error_page 495 = @495;
location @495 { return 495 '{"status":495,"message":"Client certificate authentication error"}\n'; }

error_page 496 = @496;
location @496 { return 496 '{"status":496,"message":"Client certificate not presented"}\n'; }

error_page 497 = @497;
location @497 { return 497 '{"status":497,"message":"HTTP request was sent to mutual TLS port"}\n'; }

error_page 500 = @500;
location @500 { return 500 '{"status":500,"message":"Server error"}\n'; }

error_page 501 = @501;
location @501 { return 501 '{"status":501,"message":"Not implemented"}\n'; }

error_page 502 = @502;
location @502 { return 502 '{"status":502,"message":"Bad gateway"}\n'; }

相关内容