I am attempting to use NGINX as a reverse proxy in front of a GraphQL server and leverage NGINX caching. In my configuration, I intend to cache the response of POST API requests, considering both the request body and the API URL as part of the cache key. However, this approach is not working as expected. Even when I modify the payload of the API request, I continue to receive the same response that was cached the first time. I am unsure what is causing the issue in the configuration.
worker_processes 1;
error_log C:/Workspace/error.log;
events {
worker_connections 1024;
}
http {
# Define the cache path and settings
proxy_cache_path "C:/Users/username/Documents/cache" levels=1:2 keys_zone=my_cache:100m max_size=200m inactive=5m;
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/m;
include 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 logs/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 8081;
server_name localhost;
location /api {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host localhost;
proxy_pass http://localhost:8080;
# Enable request body buffering and set buffer size
proxy_buffers 8 32M;
proxy_buffer_size 30M;
client_body_buffer_size 10M; # Adjust this size based on your needs
# proxy_buffering on; # Enable buffering for proxy
# proxy_ignore_headers "Set-Cookie";
# proxy_hide_header "Set-Cookie";
proxy_hide_header Cache-Control;
proxy_cache_methods GET POST;
# Define the cache key based on the request scheme, method, and URI
set $cache_key "$scheme$request_method$request_uri|$request_body";
# Set a flag for whether caching should occur based on x-api-cache header
set $cache_condition 0;
if ($http_x_api_cache != "true") {
set $cache_condition 1;
}
# Enable cache only if the condition is true
proxy_cache my_cache;
proxy_cache_key $cache_key;
proxy_cache_bypass $cache_condition;
proxy_no_cache $cache_condition;
proxy_cache_valid 200 5m;
# Add the X-Cache-Status header for cache status
add_header X-Cache-Status $upstream_cache_status;
}
}
}
I'm not sure if this will directly answer your question, but it's worth a try.
First, take a look at the "Phases" [chapter] in the nginx development guide. Assigning the $cache_key
variable using the set
directive:
set $cache_key "$scheme$request_method$request_uri|$request_body";
is performed during the NGX_HTTP_REWRITE_PHASE
of the request processing. At this phase, the request body has not yet been received, so the $request_body
variable is not populated. As a result, your cache key will always have the same value, regardless of the request body content.
To ensure the $cache_key
variable is evaluated only when it is actually needed, you can use a map
block instead:
http {
...
map "" $cache_key {
default "$scheme$request_method$request_uri|$request_body";
}
server {
...
location /api {
...
# set $cache_key "$scheme$request_method$request_uri|$request_body";
# ^ remove this line!
...
}
}
}
Similarly, evaluating the $cache_condition
variable is better to be done using another map
block. There was once a famous "If is evil... when used in the location context" article (now only available via archived nginx wiki content on GitHub). Reading it carefully , particulary the "Examples" chapter, will explain why I'm suggesting the following configuration change:
http {
...
map "" $cache_key {
default "$scheme$request_method$request_uri|$request_body";
}
map $http_x_api_cache $cache_condition {
true 1;
# The following line is optional; the default value will be an empty string
default 0;
}
server {
...
location /api {
...
# set $cache_key "$scheme$request_method$request_uri|$request_body";
# ^ Remove this line!
# set $cache_condition 0;
# if ($http_x_api_cache != "true") {
# set $cache_condition 1;
# }
# ^ Remove these lines too!
...
}
}
}
I'm not entirely sure if this approach will work as intended without further testing - either in a sandbox environment or by reviewing the source code for the proxy_cache_key
directive handler. Still, it's worth trying. Any feedback or results from your testing would be greatly appreciated!