<p>h2o возвращает 304 вместо 200 в связи с php-fpm</p>

Созданный на 18 июл. 2017  ·  5Комментарии  ·  Источник: h2o/h2o

Это сводит меня с ума, но наконец-то я могу хотя бы описать проблему:
У меня есть установка CMS TYPO3, работающая в тюрьме FreeBSD. Кажется, все работает нормально, за исключением того, что в бэкэнде определенный URL-адрес возвращается с 304 вместо 200. Таким образом, загружается более старая версия контента.

И Apache (v. 2.4.27 с mod_php), и Nginx (v. 1.12.1 с php-fpm) возвращают новую страницу с HTTP-статусом 200. Последний особенно интересен, так как использует тот же php-fpm через сокет UNIX. как вода. Я даже могу остановить h2o и запустить nginx, а nginx обслуживает правильную новую версию. И наоборот, я могу остановить nginx, запустить h2o и вместо этого получить 304.

У кого-нибудь есть идея, что может быть причиной этой разницы?

Вот заголовки HTTP, когда я принудительно перезагружаю URL-адрес из h2o (CTRL + SHIFT + R):

http://testserver.local/typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit

GET /typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit HTTP/1.1
Host: testserver.local
User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:43.0) Gecko/20100101 Firefox/43.0 SeaMonkey/2.40
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: be_typo_user=9dc68c1e0a89687f525a2ae44b410ca2; PHPSESSID=bk7hs9h6vqbae93t64bv0n3b93; phpMyAdmin=bk7hs9h6vqbae93t64bv0n3b93
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache

HTTP/1.1 200 OK
Date: Tue, 18 Jul 2017 12:50:28 GMT
Connection: keep-alive
Server: h2o/2.2.2
X-Powered-By: PHP/5.6.31
Expires: 0
Last-Modified: Tue, 18 Jul 2017 12:50:28 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
x-frame-options: SAMEORIGIN
Content-Type: text/html;charset=utf-8
Content-Encoding: gzip
Vary: accept-encoding
Accept-Ranges: none
Transfer-Encoding: chunked

Обратите внимание, все заголовки, связанные с кешем, указывают на то, что эта страница не должна кэшироваться!

А вот h2o при обычной перезагрузке (STRG+R) отвечает неправильным 304:

http://testserver.local/typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit

GET /typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit HTTP/1.1
Host: testserver.local
User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:43.0) Gecko/20100101 Firefox/43.0 SeaMonkey/2.40
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: be_typo_user=9dc68c1e0a89687f525a2ae44b410ca2; PHPSESSID=bk7hs9h6vqbae93t64bv0n3b93; phpMyAdmin=bk7hs9h6vqbae93t64bv0n3b93
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
If-Modified-Since: Tue, 18 Jul 2017 12:50:28 GMT
Cache-Control: max-age=0

HTTP/1.1 304 Not Modified
Date: Tue, 18 Jul 2017 12:51:24 GMT
Connection: keep-alive
Server: h2o/2.2.2
Etag: "58f63dd6-603"
Vary: accept-encoding

Nginx и Apache всегда отвечают 200, например:

http://testserver.local/typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit

GET /typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit HTTP/1.1
Host: testserver.local
User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:43.0) Gecko/20100101 Firefox/43.0 SeaMonkey/2.40
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: be_typo_user=9dc68c1e0a89687f525a2ae44b410ca2; PHPSESSID=bk7hs9h6vqbae93t64bv0n3b93; phpMyAdmin=bk7hs9h6vqbae93t64bv0n3b93
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
If-Modified-Since: Tue, 18 Jul 2017 12:48:18 GMT
Cache-Control: max-age=0

HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Tue, 18 Jul 2017 12:49:32 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.6.31
Expires: 0
Last-Modified: Tue, 18 Jul 2017 12:49:32 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
x-frame-options: SAMEORIGIN

Я пробовал разные браузеры (Firefox и Chromium), разные заголовки кэширования, HTTP/1 и HTTP/2... результат всегда один и тот же.

Это какая-то ошибка в h2o? Или какой-то параметр или переменную среды нельзя передать в php-fpm в h2o, а в Nginx и Apache?

Самый полезный комментарий

Ах, хорошая находка. Похоже, что простое перемещение динамической обработки в начале файла приведет к ожидаемому поведению:

diff --git a/lib/handler/file.c b/lib/handler/file.c
index adc95f07..c2c35cf2 100644
--- a/lib/handler/file.c
+++ b/lib/handler/file.c
@@ -619,6 +619,13 @@ static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h
         method_type = METHOD_IS_OTHER;
     }

+    /* obtain mime type */
+    if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) {
+        do_close(&generator->super, req);
+        return delegate_dynamic_request(req, req->path_normalized.len, rpath, rpath_len, mime_type);
+    }
+    assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE);
+
     /* if-non-match and if-modified-since */
     if ((if_none_match_header_index = h2o_find_header(&req->headers, H2O_TOKEN_IF_NONE_MATCH, SIZE_MAX)) != -1) {
         h2o_iovec_t *if_none_match = &req->headers.entries[if_none_match_header_index].value;
@@ -636,13 +643,6 @@ static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h
         }
     }

-    /* obtain mime type */
-    if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) {
-        do_close(&generator->super, req);
-        return delegate_dynamic_request(req, req->path_normalized.len, rpath, rpath_len, mime_type);
-    }
-    assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE);
-
     /* only allow GET or POST for static files */
     if (method_type == METHOD_IS_OTHER) {
         do_close(&generator->super, req);

@kazuho А ты как думаешь? Интуитивно кажется, что мы всегда должны вызывать обработчик cgi, когда содержимое является динамическим?

Все 5 Комментарий

Я дополнительно проверил эту проблему - на этот раз с cURL: когда браузер предоставляет заголовок If-Modified-Since , и это в течение последних 3 месяцев, я получаю 304. Когда я не предоставляю заголовок If-Modified-Since или с датой более 3 месяцев назад, я получаю правильные 200.

Это приводит меня к вопросу: эти три месяца жестко закодированы в h2o? Как я мог обойти это? Например, возможно ли удалить заголовок If-Modified-Since из этого конкретного запроса до того, как h2o действительно что-то сделает с запросом?

Нашел еще одну деталь. Я перехватил трафик fastcgi на сокете UNIX ( используя socat, как описано здесь ).

При предоставлении заголовка If-Modified-Since со временем менее 3 месяцев h2o даже не передает этот запрос на php-fpm. Он просто отвечает браузеру, отправляя 304. При использовании Nginx все по-другому. Там каждый запрос передается на сервер php-fpm. Так что действительно кажется, что проблема заключается в том, как h2o обрабатывает этот запрос.

Я смог опознать Жучка! Проблема возникает из-за того, что h2o игнорирует динамическое содержимое и просто проверяет время последнего изменения файла PHP. Если время модификации файла было по крайней мере на 1 секунду позже времени, указанного в заголовке If-Modified-Since , h2o возвращал 200, а в противном случае — 304.

Я предполагаю, что эту ошибку можно найти в /lib/handler/file.c (строки 629-637).

Нашел временное быстрое исправление .

Ах, хорошая находка. Похоже, что простое перемещение динамической обработки в начале файла приведет к ожидаемому поведению:

diff --git a/lib/handler/file.c b/lib/handler/file.c
index adc95f07..c2c35cf2 100644
--- a/lib/handler/file.c
+++ b/lib/handler/file.c
@@ -619,6 +619,13 @@ static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h
         method_type = METHOD_IS_OTHER;
     }

+    /* obtain mime type */
+    if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) {
+        do_close(&generator->super, req);
+        return delegate_dynamic_request(req, req->path_normalized.len, rpath, rpath_len, mime_type);
+    }
+    assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE);
+
     /* if-non-match and if-modified-since */
     if ((if_none_match_header_index = h2o_find_header(&req->headers, H2O_TOKEN_IF_NONE_MATCH, SIZE_MAX)) != -1) {
         h2o_iovec_t *if_none_match = &req->headers.entries[if_none_match_header_index].value;
@@ -636,13 +643,6 @@ static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h
         }
     }

-    /* obtain mime type */
-    if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) {
-        do_close(&generator->super, req);
-        return delegate_dynamic_request(req, req->path_normalized.len, rpath, rpath_len, mime_type);
-    }
-    assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE);
-
     /* only allow GET or POST for static files */
     if (method_type == METHOD_IS_OTHER) {
         do_close(&generator->super, req);

@kazuho А ты как думаешь? Интуитивно кажется, что мы всегда должны вызывать обработчик cgi, когда содержимое является динамическим?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

wujunjenny picture wujunjenny  ·  5Комментарии

proyb6 picture proyb6  ·  5Комментарии

utrenkner picture utrenkner  ·  7Комментарии

chenbd picture chenbd  ·  3Комментарии

dch picture dch  ·  5Комментарии