Nginx forwards the new HTTP QUERY method but refuses to cache it
RFC 10008 finally introduced the QUERY method, which is essentially a GET request that can carry a body. It is designed to be safe and idempotent, meaning it should be cacheable as long as the request body is included in the cache key. This solves the age-old problem of complex search queries that are too large for a URL but shouldn't be POSTs because they aren't modifying data.
I spent a morning testing if the actual infrastructure around us supports this. I built a search API that only accepts QUERY requests—anything else returns a 405 Method Not Allowed—and hosted it on a small VPS in Frankfurt to see how it behaved behind Nginx.
Testing the API with LLMs
I wanted to see if AI models could actually implement a client for this without being explicitly told to use the QUERY method. I set up the API to search an RFC index of about 9,800 entries. If you send a GET or POST, the server rejects it with an Allow: QUERY header.
I tried two different prompting strategies across eight different models. First, I explicitly told them the endpoint required the QUERY method from RFC 10008. Every single model succeeded. They all generated Python code using urllib.request.Request(url, data=body, method='QUERY'), which works because Python's standard library doesn't validate the method string.
The logs showed a clean sweep of successful hits:
QUERY /rfcs/llama-4-maverick QUERY /rfcs/deepseek-v4-pro
QUERY /rfcs/mistral-3-14b QUERY /rfcs/gemma-4-31b-it
QUERY /rfcs/glm-5-3-flash QUERY /rfcs/openai-gpt-oss-120b
QUERY /rfcs/openai-gpt-oss-20b QUERY /rfcs/minimax-m2-5
However, when I removed the explicit mention of the QUERY method and just described the API as a JSON search endpoint, every single model defaulted to POST. None of them attempted an OPTIONS request to check supported methods first.
The Nginx caching failure
The real discovery happened when I looked at the proxy layer. While Nginx happily proxies the QUERY method to the backend, it treats it as uncacheable by default.
I ran a test where I sent four identical QUERY requests. In a world where RFC 10008 is respected, the first request should hit the backend and the subsequent three should be served from the Nginx cache. Instead, I saw four distinct hits on my backend logs. For comparison, when I ran the same test with POST requests (which are generally not cached), I saw the same behavior—but when I used a standard GET, the cache worked as expected.
You can verify this yourself with a simple curl command:
printf '%s' '{"title_contains":"QUERY","limit":1}' \
| curl -s -X QUERY --data-binary @- -H 'Content-Type: application/json' http://your-proxy-ip/rfcs
If you check your Nginx access logs, you will see the QUERY request passing through, but it will never trigger a HIT in the cache status.
When to use QUERY instead of POST
If you are building a read-only API with complex filters, the temptation is to use POST because URLs have length limits and encoding nightmares. But using POST tells the rest of the internet "do not cache this."
Using QUERY is the correct architectural choice for high-performance search endpoints, but as my test shows, you can't rely on Nginx (or current LLM-generated clients) to "just work" with it yet. You'll likely need to manually configure your proxy's caching logic to recognize the method or stick to GET with heavily encoded query strings until the tooling catches up.
All Replies (3)
Finally stopped fighting with config files. Does Cloudflare handle the 502s better or is it just hiding the mess?
Stoked to see this! I want to try this tonight with my current setup. Does this work with Nginx 1.25?
So excited to finally see a privacy-first approach. I'm curious if this integrates with Obsidian or just Notion?