带有查询字符串的文件请求在 NGINX 背后的 ASP.NET 核心中失败

File requests with Query Strings failing in ASP.NET Core behind NGINX

我在 Linux 上的 NGINX 反向代理后面有一个 ASP.NET 核心站点 运行。我 运行 遇到一个问题,如果我通过代理执行文件请求并附加查询字符串(即缓存破坏),我会收到 404 错误,但如果我请求完全相同 URL 直接从应用程序(而不是通过 NGINX),它工作正常,如果我删除查询字符串,它也工作正常。

下面的示例(NGINX 代理正在侦听端口 5000,应用程序正在侦听端口 5002)...

如果我使用 url,例如: http://host-name:5000/path/file.json

我得到了正确的结果,这就是应用程序控制台输出中显示的内容:

[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://host-name:5000/path/file.json  
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://host-name:5000/path/file.json  
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
      Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware:Information: Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 400.9508ms 200 application/json

如果我使用 url,例如: http://host-name:5002/path/file.json

我得到了正确的结果,这就是应用程序控制台输出中显示的内容:

[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://host-name:5002/path/file.json  
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://host-name:5002/path/file.json  
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
      Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware:Information: Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 28.2031ms 200 application/json
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 28.2031ms 200 application/json

如果我使用 url,例如: http://host-name:5002/path/file.json?_dc=1020

我得到了正确的结果,这就是应用程序控制台输出中显示的内容:

[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://host-name:5002/path/bootstrap.json?_dc=1020  
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://host-name:5002/path/bootstrap.json?_dc=1020  
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
      Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware:Information: Sending file. Request path: '/path/file.json'. Physical path:     '/home/coreuser/debug/wwwroot/path/file.json'
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 146.8157ms 200 application/json
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 146.8157ms 200 application/json

如果我使用 url,例如: http://host-name:5000/path/file.json?_dc=1020

我收到 404 错误,这是出现在应用程序控制台输出中的内容:

[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://host-name:5000/path/file.json?_dc=1020  
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://host-name:5000/path/file.json?_dc=1020  
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 379.4175ms 404 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 379.4175ms 404 

现在,我不清楚这是否是 NGINX 弄乱了它转发给 ASP.NET 核心应用程序的问题,或者这不仅仅是 ASP.NET 核心应用程序 (and/or Kestrel) 被请求中显示的查询字符串和代理端口号的组合抛出。

NGINX 配置的相关部分如下所示:

server {
    server_name host-name;
    listen 5000 default_server;
    listen [::]:5000 default_server;
    location / {
        proxy_pass http://localhost:5002;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Path $request_uri;
    }
}

有什么想法吗?

编辑:

我已经将我的服务器块修改为如下所示:

server {
    server_name host-name;
    listen 5000 default_server;
    listen [::]:5000 default_server;
    root /var/www/path-to-debug/wwwroot;
    location / {
        if ($query_string ~ "^(.*)_dc=(.*)$") {
          rewrite ^(.*)$ $uri?;
        }
        try_files $uri @proxy;
    }
    location @proxy {
        proxy_pass http://localhost:5002;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Path $request_uri;
    }
}

现在正在正确获取特定文件(完全绕过 Kestrel),但这似乎干扰了我的控制器调用之一,该调用还附加了 _dc=XXXX。

我已经通过修改我的服务器代理块来使这部分工作,如下所示...这对我来说感觉像是一个 hack,但我还没有找到更好的解决方案。我还有其他问题,但 post 会针对那些 if/when 我无法解决的问题单独提出问题。

server {
    server_name host-name;
    listen 5000 default_server;
    listen [::]:5000 default_server;
    root /var/www/path-to-debug/wwwroot;
    location / {
        if ($query_string ~ "^(.*)_dc=(.*)$") {
          rewrite ^(.*)$ $uri?;
        }
        try_files $uri @proxy;
    }
    location @proxy {
        proxy_pass http://localhost:5002;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Path $uri;
    }
}