У меня есть прокси-сервер кеша nginx, который получает контент с исходного сервера apache.
Я делаю запросы от curl
, wget
и Chrome
для проверки ответа кеша. Проблема в том, что для одного и того же URL я всегда получаю MISS
впервые у каждого отдельного клиента.
Я ожидал, что после того, как я сделаю один запрос от любого клиента, другие клиенты получат HIT
, но я получаю MISS
.
Я получаю только HIT
при повторении запроса в одном и том же клиенте.
Кажется, что ключ связан с пользовательским агентом, но это не так:
proxy_cache_key $scheme://$host$request_uri;
Чтобы исключить другую версию HTTP и пользовательский агент, я выделил их в запросах (по умолчанию wget использует http1.1), они оба отображаются как GET
в журналах, так что не HEAD
wget --server-response --user-agent "foo" 'https://www.example.com/x.php?124'
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Tue, 03 Mar 2020 19:53:53 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.4.16
X-Accel-Expires: 3600
Vary: Accept-Encoding
X-Cache: MISS <<<<<<<<<<<<<<<<<<<<<<<<<< there
# repeating the request again with WGET will get a HIT
wget --server-response --user-agent "foo" 'https://www.example.com/x.php?124'
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Tue, 03 Mar 2020 19:55:21 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.4.16
X-Accel-Expires: 3600
Vary: Accept-Encoding
X-Cache: HIT <<<<<<<<<<<<<<<<<<<<<<<<<<< there
# after request should be cached, a CURL request to same URL gets MISS again
curl -L -i --http1.1 --user-agent "foo" 'https://www.example.com/x.php?124'
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Tue, 03 Mar 2020 19:56:37 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.4.16
X-Accel-Expires: 3600
Vary: Accept-Encoding
X-Cache: MISS <<<<<<<<<<<<<<<<<<<<<<<<<<< there
Моя конфигурация
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
# lower value might show error: "upstream sent too big header"
proxy_buffer_size 128k;
proxy_buffers 8 256k;
proxy_busy_buffers_size 256k;
# fixes error request entity too large when uploading files
client_max_body_size 256M;
# main cache for images and some of the html pages
proxy_cache_path /nginx_cache levels=1:2 keys_zone=nginx_cache:512m max_size=50g
inactive=90d use_temp_path=off;
# deliver a cached copy in case of error at source server
proxy_cache_background_update on;
proxy_cache_use_stale updating error timeout http_500 http_502 http_503 http_504;
proxy_cache_key $scheme://$host$request_uri;
# set http version between nginx and origin servr, you can check the version in origin server log
proxy_http_version 1.1;
# enable gzip after we forced plain-text between cache and origin with Accept "" in some vhosts
gzip_types text/plain text/css text/xml text/javascript application/javascript application/x-javascript application/xml image/jpeg image/png image/webp image/gif image/x-icon image/svg;
gzip on;
# security headers, iframe block, etc
add_header X-Frame-Options sameorigin;
add_header X-Content-Type-Options nosniff;
add_header Strict-Transport-Security max-age=2678400;
# default server(s) that don't match any specified hosts
server {
server_name _;
listen 80 default_server;
listen 443 ssl http2 default_server;
root /var/www/html;
}
# include all our custom vhosts
include /etc/nginx/adr_vhosts/*.conf;
} # end of http
Моя конфигурация vhost
server {
listen 443 ssl http2;
server_name www.example.com;
root /usr/share/nginx/html;
location / {
# using the alt port to bypass the other nginx cache at source server (and X-Real-IP overwrite)
proxy_pass http://xx.xx.xx.xx:81;
proxy_cache nginx_cache;
# ask directly for the right host (including www), to avoid mismatches, additional redirects
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# sub_filter only works on plain text, disable gzip communication with origin server
proxy_set_header Accept-Encoding "";
# was it a hit or a miss
add_header X-Cache $upstream_cache_status;
# keep the x-accel header for debugging purposes
proxy_pass_header "X-Accel-Expires";
}
}
Я отключил сжатие gzip между кеш-сервером и исходным сервером с помощью proxy_set_header Accept-Encoding "";
чтобы использовать sub_filter
в каком-то месте. Затем я повторно активировал gzip с помощью gzip_types
и gzip on
.
Внутри /nginx_cache
для каждого клиента сохраняется файл кеша, эти два предназначены для nginx и wget, анимация переключается между двумя файлами, чтобы увидеть, что они почти идентичны, за исключением двоичных (или gzip ?!) данных выше:
Редактировать: Я получаю HIT
со всеми клиентами, если я укажу Accept-Encoding: gzip
в запросе ! Я займусь этим ...
Изменить 2: wget отправляет заголовок запроса Accept-Encoding: identity
, curl по умолчанию вообще не отправляет, а Chrome отправляет Accept-Encoding: gzip, deflate, br
, кеш правильно получает удар, если я принудительно выставляю им любое значение, пока они одинаковы. Это неправильная конфигурация с моей стороны или это нормальное поведение? Он действует так, как будто accept-encoding является частью cache_key.
Я отвечаю на свой вопрос, чтобы прояснить длинные детали в вопросе и частично опубликовать решение ...
Я обнаружил, что разные клиенты (Curl vs Wget vs Chrome) получают MISS
кешировать ответы один за другим для одного и того же URL-адреса из-за vary: Accept-Encoding
в заголовках ответа (например, создать другой кеш варидля каждого Accept-Encoding)
Chrome: Accept-Encoding: gzip, deflate, br
Wget: Accept-Encoding: identify
Curl: n/a
В Vary: Accept-Encoding
похоже, исходит с моего исходного сервера, и я подтвердил, что кеш всегда возвращает HIT
если я добавлю:
proxy_ignore_headers Vary;
Просто я не уверен, безопасно ли это делать, я открою Другой вопрос для этого.