【问题标题】:How to cache one particular reverse-proxied route in NGINX?如何在 NGINX 中缓存一个特定的反向代理路由?
【发布时间】:2016-06-04 15:49:23
【问题描述】:

我使用 nginx 作为反向代理,这是我的配置中的一个 sn-p,它将 /api 调用下的任何内容路由到内部 API 服务器:

  # API server
  location /api {
    if ($request_method = OPTIONS) {
      return 204;
    }

    # Proxy settings
    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_pass http://my.api-server.com

    # Error handlers
    error_page 504 /errors/504.json;

    # CORS headers
    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Allow' '*' always;
    add_header 'Access-Control-Allow-Methods' 'GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Referrer, User-Agent, Authorization, X-Impersonate-As, X-Request-Context' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Expose-Headers' 'Authorization, X-Request-Id, X-Server-Time' always;
    add_header 'Access-Control-Max-Age' 3628800;
  }

但现在我想允许一个规则缓存一个特定的反向代理路由(比如/api/foo/bar,TTL = 30 分钟),我尝试了这个:

  location /api {
    if ($request_method = OPTIONS) {
      return 204;
    }
    if ($request_uri ~* /api/foo/bar) {
      proxy_cache_valid 200 301 302 30m;
      add_header X-Cache $upstream_cache_status;
    }
    ....

但是,这行不通。最好的方法是什么?

编辑:

完整的服务器配置:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

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"';

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

    sendfile        on;
    #tcp_nopush     on;

    gzip  on;
    gzip_http_version 1.1;
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_vary on;
    gzip_types text/plain
               text/xml
               text/css
               text/javascript
               application/json
               application/javascript
               application/x-javascript
               application/ecmascript
               application/xml
               application/rss+xml
               application/atom+xml
               application/rdf+xml
               application/xml+rss
               application/xhtml+xml
               application/x-font-ttf
               application/x-font-opentype
               application/vnd.ms-fontobject
               image/svg+xml
               image/x-icon
               application/atom_xml;

    gzip_buffers 16 8k;

    add_header X-Frame-Options SAMEORIGIN;

    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

    keepalive_timeout           60;
    proxy_connect_timeout       60;
    proxy_send_timeout          60;
    proxy_read_timeout          60;
    send_timeout                60;

    client_max_body_size 100M;

    proxy_cache_path /dev/shm levels=1:2 keys_zone=mcache:16m inactive=600s max_size=512m;
    proxy_cache_methods GET HEAD;
    proxy_cache_min_uses 1;
    proxy_cache_key "$request_method$host$request_uri";
    proxy_cache_use_stale timeout updating;
    proxy_ignore_headers Cache-Control Expires Set-Cookie;

    server {
      listen 80;
      server_name my.company.com;
      return 301 https://$host$request_uri;
    }

  server {
    listen 443 http2 default_server ssl;

    server_name my.company.com;

    ssl_certificate     /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/cert.key;
    ssl on;

    # API server
    location /api {
      if ($request_method = OPTIONS) {
        return 204;
      }

      # Proxy settings
      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_pass http://internal-api-server;

      # Error handlers
      error_page 504 /errors/504.json;

    if ($request_uri ~* /api/foo/bar) {
      proxy_cache_bypass 0;
      proxy_no_cache     0;
      proxy_cache        mcache; # mcache=RAM
      proxy_cache_valid 200 301 302  30m;
      proxy_cache_valid 403 404      5m;
      proxy_cache_lock   on;
      proxy_cache_use_stale timeout updating;
      add_header X-Proxy-Cache $upstream_cache_status;
    }

      # CORS headers
      add_header 'Access-Control-Allow-Origin' '*' always;
      add_header 'Allow' '*' always;
      add_header 'Access-Control-Allow-Methods' 'GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS' always;
      add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Referrer, User-Agent, Authorization, X-Impersonate-As, X-Request-Context' always;
      add_header 'Access-Control-Allow-Credentials' 'true' always;
      add_header 'Access-Control-Expose-Headers' 'Authorization, X-Info-Resources' always;
      add_header 'Access-Control-Max-Age' 3628800 always;
    }

    location ^~ /errors/ {
      internal;
      root /etc/nginx/static-files/;
    }

    location /nginx_status {
      stub_status on;
      access_log off;
    }
  }
}

【问题讨论】:

  • @peixotorms:我把完整的cat /etc/nginx/nginx.conf 放在上面的编辑中

标签: caching nginx proxy reverse-proxy nginx-location


【解决方案1】:

有几件事需要调查:

  1. Nginx 默认只缓存 GET 和 HEAD 请求。
  2. 默认情况下,Nginx 不会缓存任何 POST 或任何带有 COOKIES 的内容。

在使用 cookie 时强制缓存:

proxy_ignore_headers Cache-Control Expires Set-Cookie;

与其他请求方法一起缓存(选择您自己的):

proxy_cache_methods GET HEAD POST PUT DELETE PATCH OPTIONS;

===

编辑:

试试这些设置:

在 /etc/nginx/nginx.conf 上

proxy_cache_path /dev/shm levels=1:2 keys_zone=mcache:16m inactive=600s max_size=512m;
proxy_cache_methods GET HEAD;
proxy_cache_min_uses 1;
proxy_cache_key "$request_method$host$request_uri";
proxy_cache_use_stale timeout updating;
proxy_ignore_headers Cache-Control Expires Set-Cookie;

在您的位置块上:

location /api/foo/bar {
    proxy_cache_bypass 0;
    proxy_no_cache     0;
    proxy_cache        mcache; # mcache=RAM
    proxy_cache_valid 200 301 302  30m;
    proxy_cache_valid 403 404      5m;
    proxy_cache_lock   on;
    proxy_cache_use_stale timeout updating;
    add_header X-Proxy-Cache $upstream_cache_status;
}

确保 Nginx 已重新加载(或停止 + 启动)

service nginx reload

用 curl 测试:

curl -X GET -I https://yoururl

【讨论】:

  • 谢谢,但这是一个简单的 GET,并且(还)不涉及 cookie。我正在命令行中从curl 尝试。
  • 请发布您的完整 nginx.conf 以及相关配置,例如位置块和包含的 conf 文件。 curl返回的headers是什么?
  • 我添加了完整的服务器块。 /api/foo/bar 的 curl 仅返回代理的标头(所以我知道它会进入 IF 块),而其他 API 也确实返回其余的 Access-Control 标头。
  • 虽然服务器块很有用。例如,它不会告诉我,如果您在服务器上设置了 proxy_cache_pathproxy_cache_key(除其他外)。请发布您的nginx.conf 文件。
  • 抱怨 nginx: [emerg] "proxy_cache_bypass" directive is not allowed here in /etc/nginx/nginx.conf:107 - 它不喜欢 if 块中的任何 proxy_pass 设置
【解决方案2】:

确保您指定了 proxy_cache_path(或者您的示例中没有包含它?)

【讨论】:

    猜你喜欢
    • 2019-06-05
    • 2021-11-22
    • 2021-05-03
    • 2019-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 2011-06-27
    相关资源
    最近更新 更多