nginx返回base64编码字符串中的自定义503页面,而不仅仅是html

fhg3lkii  于 2023-11-17  发布在  Nginx
关注(0)|答案(1)|浏览(244)

我在nginx上有一个奇怪的错误,当我试图在nginx上实现一个自定义的503错误页面时,我的维护期。
我的自定义页面位于/opt/app_name/maintenance_on. html
我的nginx配置看起来像这样:

  1. server {
  2. listen 80;
  3. server_name app-name;
  4. root /opt/app_name;
  5. proxy_set_header X-Forwarded-Host $host;
  6. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  7. proxy_set_header X-Forwarded-Proto $scheme;
  8. proxy_set_header X-Real-IP $remote_addr;
  9. add_header X-Frame-Options "SAMEORIGIN";
  10. add_header X-XSS-Protection "1; mode=block";
  11. proxy_set_header X-Client-IP $remote_addr;
  12. proxy_set_header HTTP_X_FORWARDED_HOST $remote_addr;
  13. access_log /var/log/nginx/app-name-access.log;
  14. error_log /var/log/nginx/app-name-error.log;
  15. proxy_buffers 16 64k;
  16. proxy_buffer_size 128k;
  17. proxy_read_timeout 900s;
  18. proxy_connect_timeout 900s;
  19. proxy_send_timeout 900s;
  20. proxy_next_upstream error timeout invalid_header http_500 http_502
  21. http_503;
  22. types {
  23. text/less less;
  24. text/scss scss;
  25. }
  26. gzip on;
  27. gzip_min_length 1100;
  28. gzip_buffers 4 32k;
  29. gzip_types text/css text/less text/plain text/xml application/xml applicatio>
  30. gzip_vary on;
  31. client_header_buffer_size 4k;
  32. large_client_header_buffers 4 64k;
  33. client_max_body_size 0;
  34. location / {
  35. if (-f /opt/app_name/maintenance_on.html) {
  36. return 503;
  37. }
  38. proxy_pass http://127.0.0.1:XXXX;
  39. proxy_redirect off;
  40. }
  41. location /longpolling {
  42. proxy_pass http://127.0.0.1:XXXX;
  43. }
  44. location ~* .(js|css|png|jpg|jpeg|gif|ico)$ {
  45. expires 2d;
  46. proxy_pass http://127.0.0.1:XXXX;
  47. add_header Cache-Control "public, no-transform";
  48. }
  49. location ~ /[a-zA-Z0-9_-]*/static/ {
  50. proxy_cache_valid 200 302 60m;
  51. proxy_cache_valid 404 1m;
  52. proxy_buffering on;
  53. expires 864000;
  54. proxy_pass http://127.0.0.1:XXX;
  55. }
  56. error_page 503 @maintenance;
  57. location @maintenance {
  58. rewrite ^(.*)$ /maintenance_on.html break;
  59. }
  60. }

字符串
页面看起来像这样:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
  5. <title>Performing Maintenance</title>
  6. <style type="text/css">
  7. body { text-align: center; padding: 150px; }
  8. h1 { font-size: 40px; }
  9. body { font: 20px Helvetica, sans-serif; color: #333; }
  10. #article { display: block; text-align: left; width: 650px; margin: 0 au>
  11. a { color: #dc8100; text-decoration: none; }
  12. a:hover { color: #333; text-decoration: none; }
  13. </style>
  14. </head>
  15. <body>
  16. <div id="article">
  17. <h1>The system is currently getting some Updates.</h1>
  18. <div>
  19. <p>We apologize for the inconvenience, but we're performing some mainte>
  20. <p>&mdash; Maintainer</p>
  21. </div>
  22. </div>
  23. </body>
  24. </html>


这个配置的问题是,nginx像预期的那样重定向到503,但是响应包含的html页面是base64编码的字符串,而不是html页面。所以浏览器不会显示任何东西。

xmjla07d

xmjla07d1#

虽然根本原因尚不清楚,但我能够找到解决方案。

TL;DR

  1. default_type text/html;

字符串

分析

在这些配置用例中,唯一会发生变化的是add_headerdefault_type语句。

案例1:HTTP 200可以正常工作,但具有重复的标头

HTTP状态代码200似乎使nginx使用给定的头,尽管它得到了重复。

配置

  1. server {
  2. listen 443 ssl http2;
  3. server_name ${SITES};
  4. ssl_certificate ${CERTLOC}/${SITE}/fullchain.pem;
  5. ssl_certificate_key ${CERTLOC}/${SITE}/privkey.pem;
  6. location / {
  7. add_header Content-Type text/html;
  8. return 200 '<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>';
  9. }
  10. }

响应

  1. $ curl -I https://maintenance.molnix.com; echo ""; curl https://maintenance.molnix.com; echo ""
  2. HTTP/2 200
  3. server: nginx
  4. date: Tue, 07 Nov 2023 06:35:46 GMT
  5. content-type: application/octet-stream
  6. content-length: 383
  7. content-type: text/html
  8. <!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>

案例2:HTTP 503不起作用

将HTTP状态代码更改为503(与502相同,可能是其他代码)似乎会使nginx忽略内容类型头,并导致浏览器依赖于默认的八位字节流。

配置

  1. server {
  2. listen 443 ssl http2;
  3. server_name ${SITES};
  4. ssl_certificate ${CERTLOC}/${SITE}/fullchain.pem;
  5. ssl_certificate_key ${CERTLOC}/${SITE}/privkey.pem;
  6. location / {
  7. add_header Content-Type text/html;
  8. return 503 '<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>';
  9. }
  10. }

响应

  1. $ curl -I https://maintenance.molnix.com; echo ""; curl https://maintenance.molnix.com; echo ""
  2. HTTP/2 503
  3. server: nginx
  4. date: Tue, 07 Nov 2023 06:39:06 GMT
  5. content-type: application/octet-stream
  6. content-length: 383
  7. <!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>

用例3:HTTP 503按预期工作

在这里,只设置默认类型会导致表面上nginx强制的头本身被更改,而不需要进一步的设置。因为它不是add_header语句,所以它还具有允许继承其他头的好处,这降低了配置的复杂性。

配置

  1. server {
  2. listen 443 ssl http2;
  3. server_name ${SITES};
  4. ssl_certificate ${CERTLOC}/${SITE}/fullchain.pem;
  5. ssl_certificate_key ${CERTLOC}/${SITE}/privkey.pem;
  6. default_type text/html;
  7. location / {
  8. return 503 '<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>';
  9. }
  10. }

响应

  1. $ curl -I https://maintenance.molnix.com; echo ""; curl https://maintenance.molnix.com; echo ""
  2. HTTP/2 503
  3. server: nginx
  4. date: Tue, 07 Nov 2023 06:39:44 GMT
  5. content-type: text/html
  6. content-length: 383
  7. strict-transport-security: max-age=15768000
  8. <!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>

注解

  • 最后一个响应中的HSTS头来自conf.d,在此站点配置中不使用头语句时会保留该头。对于OP情况,可以忽略响应的该部分。
  • curl似乎可以自动解码base64,这与浏览器完全不同,在浏览器中,响应和页面根本不呈现,或者浏览器对八位字节流进行编码(如果还没有)。我没有检查原始数据流来确认,因为它不会影响实际意义。
  • 如果您正在试用这些配置,请将${SITES}替换为您的站点,例如我们使用maintenance.molnix.com,将${CERTLOC}/${SITE}替换为您的证书路径-在本示例中,此路径遵循Let's Encrypt约定,分别为/etc/letsencrypt/livemaintenance.molnix.com
  • 在Ubuntu 22.04 LTS库存软件包上测试
展开查看全部

相关问题