I have a simple nginx configuration for the /info
location.
location /info {
uwsgi_read_timeout 20s;
uwsgi_send_timeout 20s;
uwsgi_pass unix:///tmp/uwsgi.sock;
include uwsgi_params;
}
This location needs to be cached. So I added
proxy_cache info_cache;
proxy_cache_valid 200 10m;
to this configuration. It worked fine.
After a while, we realized some old buggy clients of our app are sending the header If-None-Match
, and nginx deliveries 304 Not Modified
as expected. The problem is these clients are waiting for a 200 OK
plus a response body. Unfortunately, we are not being able to fix them all.
Is it possible to have nginx ignoring If-None-Match
and still delivering from cache?
After a few tests, even by dropping the header value, proxy_set_header If-None-Match "";
, if the content comes from the cache, nginx checks If-None-Match
. Remembering it's from the proxy pass, not static.
Best Answer
Have you tried changing http://nginx.org/r/if_modified_since from the default of
exact
tooff
?Based on my reading of
src/http/modules/ngx_http_not_modified_filter_module.c
::ngx_http_not_modified_header_filter()
:If the header
If-Modified-Since
is present (and is non-empty), and theif_modified_since
directive is set tooff
(beingNGX_HTTP_IMS_OFF
define
in the source code), thenngx_http_test_if_modified()
immediately returns true, resulting in the filter shortcircuiting withreturn ngx_http_next_header_filter(r)
; in other words, in such a case, theIf-None-Match
logic wouldn't be executing.Note that this happens only if the
If-Modified-Since
header is actually present (and non-empty) in the request (in addition toIf-None-Match
that you're dealing with), otherwise, the code path will continue without theNGX_HTTP_IMS_OFF
setting having any effect; I think the expectation here is that if the clients already includeIf-None-Match
, thenIf-Modified-Since
is likely included as well; thus, there doesn't seem to be a separate option to disable processing ofIf-None-Match
specifically and individually.Note that
ETag
support, together with theIf-None-Match
, is only available instable-1.4
and above (it's not present instable-1.2
and below), so, downgrading might also be an option.Have you tried clearing the
ETag
before the client?Do your clients send
If-None-Match: *
? If so, then as per https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26, not performing the GET action would be correct (e.g., returning304 Not Modified
is entirely correct), and that's exactly what nginx does, which can easily be verified by running something likecurl -H"If-None-Match: *" -v localhost:80
on a default installation with nginx/1.15.9 (note thatstable-1.2
doesn't haveETag
orIf-None-Match
support, as they first appeared withstable-1.4
).If not, you might try to omit the
ETag
in your responses to trick the clients to not send anIf-None-Match
.You can use http://nginx.org/r/add_header to clear the
ETag
header from responses to the clients:BTW, I've also tried modifying
$http_if_none_match
directly with http://nginx.org/r/set, but it didn't have any effect.As a final resort, if a better solution isn't available (although I think that the above solutions might as well work), what you could do is put another instance of nginx in front of your regular caching nginx specifically for those buggy clients. In this new nginx instance, you'd disable all sorts of caching, remove the header that's not handled correctly by your buggy client apps, and pass the request to the normal instance of nginx that does do the caching.
More specifically, you might want to make sure that this new instance wouldn't do any buffering, either, http://nginx.org/r/proxy_buffering, otherwise, you risk getting your performance reduced by an extra step of saving stuff to disk all over again by the extra instance; else, it should all be copied in memory, and will likely be fast enough.
I think this approach should definitely work, because this frontline nginx wouldn't have any cache, thus, it couldn't possibly reply with
304 Not Modified
, whereas the backend nginx wouldn't receive theIf-None-Match
if you clear theIf-None-Match
on the frontend nginx with http://nginx.org/r/proxy_set_header before doing a http://nginx.org/r/proxy_pass to the backend nginx.P.S. The other answer suggests using http://nginx.org/r/proxy_ignore_headers, but, based on documentation around it as well as around http://nginx.org/r/proxy_set_header, it doesn't seem like sprinkling
If-None-Match
should make any difference; plus, it looks like there's no_set_header
variant foruwsgi
anyways.P.P.S. Another potential avenue, if you don't actually need to deliver things from cache, is changing http://nginx.org/r/uwsgi_cache_revalidate from the default of
off
toon
; however, I think this, too, would depend on_set_header
, which is missing in theuwsgi
version.