Php сокеты сервер не возвращает ответ: Делаем вебсокеты на PHP с нуля / Хабр
Сокеты PHP -принимать несколько подключений
Текущий верхний ответ здесь неверен, вам не нужно несколько потоков для обработки нескольких клиентов. Вы можете использовать неблокирующий ввод-вывод и stream_select
/socket_select
для обработки сообщений от клиентов, требующих действий. Я бы рекомендовал использовать stream_socket_*
функции над socket_*
.
Хотя неблокирующий ввод-вывод работает вполне нормально, вы не можете выполнять какие-либо вызовы функций с включением блокирующего ввода-вывода, в противном случае блокирующий ввод-вывод блокирует весь процесс, и все клиенты зависают, а не только один.
Это означает, что весь ввод-вывод должен быть неблокирующим или гарантированно очень быстрым (что не идеально, но может быть приемлемо). Поскольку не только ваши сокеты должны использовать stream_select
, но вам нужно выбиратьвсеоткрытые потоки, я бы порекомендовал библиотеку, которая предлагает регистрировать наблюдатели чтения и записи, которые выполняются один раз в потоке. становится доступным для чтения/записи.
Доступно несколько таких фреймворков, самые распространенные из них -ReactPHP и АТАГ-1|, Базовые циклы событий очень похожи, но Amp предлагает еще несколько функций на этой стороне.
Основное различие между ними -подход к API. В то время как ReactPHP повсюду использует обратные вызовы, Amp пытается избежать их, используя сопрограммы и оптимизируя свои API для такого использования.
Руководство Amp«Начало работы»в основном посвящено этой теме. Вы можете прочитать полное руководство here. Ниже я приведу рабочий пример.
ПРЕКОД-0|
Loop::run()
запускает цикл обработки событий и отслеживает события таймера, сигналы и потоки действий, которые могут быть зарегистрированы с помощью Loop::on*()
методы. Серверный сокет создается с помощью Amp\Socket\listen()
. Server::accept()
возвращает Promise
который можно использовать для ожидания новых клиентских подключений. После того, как клиент принят, он выполняет сопрограмму, которая читает от клиента и отправляет ему те же данные. Для получения дополнительных сведений см. Документацию Amp.
Информационные | |||
---|---|---|---|
100 | Continue | «Продолжить». Этот промежуточный ответ указывает, что запрос успешно принят и клиент может продолжать присылать запросы либо проигнорировать этот ответ, если запрос был завершён. | Только HTTP/1.1 |
101 | Switching Protocol | «Переключение протокола». Этот код присылается в ответ на запрос клиента, содержащий заголовок Upgrade: , и указывает, что сервер переключился на протокол, который был указан в заголовке. Эта возможность позволяет перейти на несовместимую версию протокола и обычно не используется. | Только HTTP/1.1 |
102 | Processing | «В обработке». Этот код указывает, что сервер получил запрос и обрабатывает его, но обработка еще не завершена. | Только HTTP/1.1 |
103 | Early Hints | «Ранние подсказки». В ответе сообщаются ресурсы, которые могут быть загружены заранее, пока сервер будет подготавливать основной ответ. RFC 8297 (Experimental). | Только HTTP/1.1 |
Успешные | |||
200 | OK | «Успешно». Запрос успешно обработан. Что значит «успешно», зависит от метода HTTP, который был запрошен:
| HTTP/0.9 и выше |
201 | Created | «Создано». Запрос успешно выполнен и в результате был создан ресурс. Этот код обычно присылается в ответ на запрос PUT «ПОМЕСТИТЬ». | HTTP/0.9 и выше |
202 | Accepted | «Принято». Запрос принят, но ещё не обработан. Не поддерживаемо, т.е., нет способа с помощью HTTP отправить асинхронный ответ позже, который будет показывать итог обработки запроса. Это предназначено для случаев, когда запрос обрабатывается другим процессом или сервером, либо для пакетной обработки. | HTTP/0.9 и выше |
203 | Non-Authoritative Information | «Информация не авторитетна». Этот код ответа означает, что информация, которая возвращена, была предоставлена не от исходного сервера, а из какого-нибудь другого источника. Во всех остальных ситуациях более предпочтителен код ответа 200 OK. | HTTP/0.9 и 1.1 |
204 | No Content | «Нет содержимого». Нет содержимого для ответа на запрос, но заголовки ответа, которые могут быть полезны, присылаются. Клиент может использовать их для обновления кешированных заголовков полученных ранее для этого ресурса. | HTTP/0.9 и выше |
205 | Reset Content | «Сбросить содержимое». Этот код присылается, когда запрос обработан, чтобы сообщить клиенту, что необходимо сбросить отображение документа, который прислал этот запрос. | Только HTTP/1.1 |
206 | Partial Content | «Частичное содержимое». Этот код ответа используется, когда клиент присылает заголовок диапазона, чтобы выполнить загрузку отдельно, в несколько потоков. | Только HTTP/1.1 |
Сообщения о перенаправлениях | |||
300 | Multiple Choice | «Множественный выбор». Этот код ответа присылается, когда запрос имеет более чем один из возможных ответов. И User-agent или пользователь должен выбрать один из ответов. Не существует стандартизированного способа выбора одного из полученных ответов. | HTTP/1.0 and later |
301 | Moved Permanently | «Перемещён на постоянной основе». Этот код ответа значит, что URI запрашиваемого ресурса был изменен. Возможно, новый URI будет предоставлен в ответе. | HTTP/0.9 and later |
302 | Found | «Найдено». Этот код ответа значит, что запрошенный ресурс временно изменен. Новые изменения в URI могут быть доступны в будущем. Таким образом, этот URI, должен быть использован клиентом в будущих запросах. | HTTP/0.9 and later |
303 | See Other | «Просмотр других ресурсов». Этот код ответа присылается, чтобы направлять клиента для получения запрашиваемого ресурса в другой URI с запросом GET. | HTTP/0.9 and 1.1 |
304 | Not Modified | «Не модифицировано». Используется для кэширования. Это код ответа значит, что запрошенный ресурс не был изменен. Таким образом, клиент может продолжать использовать кэшированную версию ответа. | HTTP/0.9 and later |
305 | Use Proxy | «Использовать прокси». Это означает, что запрошенный ресурс должен быть доступен через прокси. Этот код ответа в основном не поддерживается из соображений безопасности. | HTTP/1.1 only |
306 | Switch Proxy | Больше не использовать. Изначально подразумевалось, что » последующие запросы должны использовать указанный прокси.» | HTTP/1.1 only |
307 | Temporary Redirect | «Временное перенаправление». Сервер отправил этот ответ, чтобы клиент получил запрошенный ресурс на другой URL-адрес с тем же методом, который использовал предыдущий запрос. Данный код имеет ту же семантику, что код ответа 302 Found , за исключением того, что агент пользователя не должен изменять используемый метод HTTP: если в первом запросе использовался POST , то во втором запросе также должен использоваться POST . | HTTP/1.1 only |
308 | Permanent Redirect | «Перенаправление на постоянной основе». Это означает, что ресурс теперь постоянно находится в другом URI, указанном в заголовке Примечание: Это экспериментальный код ответа, Спецификация которого в настоящее время находится в черновом виде. | draft-reschke-http-status-308 |
Клиентские | |||
400 | Bad Request | «Плохой запрос». Этот ответ означает, что сервер не понимает запрос из-за неверного синтаксиса. | HTTP/0.9 and later |
401 | Unauthorized | «Неавторизованно». Для получения запрашиваемого ответа нужна аутентификация. Статус похож на статус 403, но,в этом случае, аутентификация возможна. | HTTP/0.9 and later |
402 | Payment Required | «Необходима оплата». Этот код ответа зарезервирован для будущего использования. Первоначальная цель для создания этого когда была в использовании его для цифровых платежных систем(на данный момент не используется). | HTTP/0.9 and 1.1 |
403 | Forbidden | «Запрещено». У клиента нет прав доступа к содержимому, поэтому сервер отказывается дать надлежащий ответ. | HTTP/0.9 and later |
404 | Not Found | «Не найден». Сервер не может найти запрашиваемый ресурс. Код этого ответа, наверно, самый известный из-за частоты его появления в вебе. | HTTP/0.9 and later |
405 | Method Not Allowed | «Метод не разрешен». Сервер знает о запрашиваемом методе, но он был деактивирован и не может быть использован. Два обязательных метода, GET и HEAD , никогда не должны быть деактивированы и не должны возвращать этот код ошибки. | HTTP/1.1 only |
406 | Not Acceptable | Этот ответ отсылается, когда веб сервер после выполнения server-driven content negotiation, не нашел контента, отвечающего критериям, полученным из user agent. | HTTP/1.1 only |
407 | Proxy Authentication Required | Этот код ответа аналогичен коду 401, только аутентификация требуется для прокси сервера. | HTTP/1.1 only |
408 | Request Timeout | Ответ с таким кодом может прийти, даже без предшествующего запроса. Он означает, что сервер хотел бы отключить это неиспользуемое соединение. Этот метод используется все чаще с тех пор, как некоторые браузеры, вроде Chrome и IE9, стали использовать HTTP механизмы предварительного соединения для ускорения серфинга (смотрите баг 634278, будущей реализации этого механизма в Firefox). Также учитывайте, что некоторые серверы прерывают соединения не отправляя подобных сообщений. | HTTP/1.1 only |
409 | Conflict | Этот ответ отсылается, когда запрос конфликтует с текущим состоянием сервера. | HTTP/1.1 only |
410 | Gone | Этот ответ отсылается, когда запрашиваемый контент удален с сервера. | HTTP/1.1 only |
411 | Length Required | Запрос отклонен, потому что сервер требует указание заголовка | HTTP/1.1 only |
412 | Precondition Failed | Клиент указал в своих заголовках условия, которые сервер не может выполнить | HTTP/1.1 only |
413 | Request Entity Too Large | Размер запроса превышает лимит, объявленный сервером. Сервер может закрыть соединение, вернув заголовок | HTTP/1.1 only |
414 | Request-URI Too Long | URI запрашиваемый клиентом слишком длинный для того, чтобы сервер смог его обработать | HTTP/1.1 only |
415 | Unsupported Media Type | Медиа формат запрашиваемых данных не поддерживается сервером, поэтому запрос отклонен | HTTP/1.1 only |
416 | Requested Range Not Satisfiable | Диапазон указанный заголовком запроса Range не может быть выполнен; возможно, он выходит за пределы переданного URI | HTTP/1.1 only |
417 | Expectation Failed | Этот код ответа означает, что ожидание, полученное из заголовка запроса Expect , не может быть выполнено сервером. | HTTP/1.1 only |
Серверные | |||
500 | Internal Server Error | «Внутренняя ошибка сервера». Сервер столкнулся с ситуацией, которую он не знает как обработать. | HTTP/0.9 and later |
501 | Not Implemented | «Не выполнено». Метод запроса не поддерживается сервером и не может быть обработан. Единственные методы, которые сервера должны поддерживать (и, соответственно, не должны возвращать этот код) — GET и HEAD . | HTTP/0.9 and later |
502 | Bad Gateway | «Плохой шлюз». Эта ошибка означает что сервер, во время работы в качестве шлюза для получения ответа, нужного для обработки запроса, получил недействительный (недопустимый) ответ. | HTTP/0.9 and later |
503 | Service Unavailable | «Сервис недоступен». Сервер не готов обрабатывать запрос. Зачастую причинами являются отключение сервера или то, что он перегружен. Обратите внимание, что вместе с этим ответом удобная для пользователей(user-friendly) страница должна отправлять объяснение проблемы. Этот ответ должен использоваться для временных условий и Retry-After: HTTP-заголовок должен, если возможно, содержать предполагаемое время до восстановления сервиса. Веб-мастер также должен позаботиться о заголовках, связанных с кэшем, которые отправляются вместе с этим ответом, так как эти ответы, связанные с временными условиями, обычно не должны кэшироваться. | HTTP/0.9 and later |
504 | Gateway Timeout | Этот ответ об ошибке предоставляется, когда сервер действует как шлюз и не может получить ответ вовремя. | HTTP/1.1 only |
505 | HTTP Version Not Supported | «HTTP-версия не поддерживается». HTTP-версия, используемая в запросе, не поддерживается сервером. | HTTP/1.1 only |
Nginx timeout
__group__ ticket summary owner component _version priority severity milestone type _status workflow _created modified _description _reporter Needs Dev / Bug Wrangler Feedback 39740 «Twenty Seventeen: Allow child themes to use front-page.php when front page is set to «»Your Latest Posts»»» Bundled Theme 4.7 high normal Awaiting Review defect (bug) reopened dev-feedback 2017-01-30T19:54:05Z 2017 … sudo service nginx reload I have used a rather large value that is unlikely to happen, i.e. 999999 or using time units, to one day via 1d. Beware that setting the value to 0 will cause a gateway timeout error immediately.
Convertible top installers
Active connections: 2340 server accepts handled requests 81769947 81769947 144332345 Reading: 0 Writing: 241 Waiting: 2092 Hi all, I have been trying to rewrite the openhab2 documentation with a tutorial with how to setup NGINX with use for openHAB2, I see a lot of questions about authentication and HTTPS and I feel these are the steps that would make it easier for people. I’m looking for any type of feedback and questions. There’s a lot of information here but I hope this helps, you can see the intended …
Sucrose ionic or covalent
NGINX and NGINX Plus can continually test your upstream servers, avoid the servers that have failed, and gracefully add the recovered servers into the load‑balanced group. Prerequisites. For passive health checks, NGINX Open Source or NGINX Plus; For active health checks and the live activity monitoring dashboard, NGINX Plus request timed out — default 60 client_body_timeout 10; # if client stop responding, free up memory Nginx default value (100) is far better. In addition, if your website is behind Cloudflare services (free…
Grand power q100 for sale
Sets a timeout for transmitting a request to the proxied server. The timeout is set only between two successive write operations, not for the transmission of the whole request. If the proxied server does not receive anything within this time, the connection is closed. Mar 09, 2020 · The default NGINX timeout is 60 seconds; if you’ve raised your PHP-FPM timeout above 60 seconds, NGINX will return a 504 Gateway Timeout error if your PHP application hasn’t responded in time. You can prevent this by also raising your NGINX timeout.
2021 nissan frontier manual transmission
Mar 08, 2011 · Nginx & Apache. Working with virtual servers (like OpenVZ containers or XEN dom’s) you might need a load balancing or a proxy solution to be able to run services from inside those machines through your host’s single public IP address. Sep 19, 2017 · The timeout is set only if a body is not get in one readstep. If after this time the client send nothing, nginx returns error “Request time out” (408). The default is 60. client_header_timeout 10; – Directive assigns timeout with reading of the title of the request of client. The timeout is set only if a header is not get in one readstep.
Lawsuit settlement tax calculator
Sep 25, 2012 · As far as I know, if the execution time on nginx-sides runs out, the php script will still be running in the background, but the user will get the “504 Gateway timeout”-error. On the other side, hitting the max-execution time for php-fpm or in php itself will kill the process, write something into the PHP log file (like “PHP Fatal error: Maximum execution time of XX seconds exceeded in”…). May 10, 2012 · Dear Nginx/Php-fpm users, I installed a new VPS for testing pressflow with nginx/php-fpm ,but I seem to have somekind of unkown issue. When I browse around on my website, installing a small modules or going to a simple page I sometimes get a nginx «504 Gateway Time-out»
Velocity on an inclined plane with friction
The problem is usually assigned to nginx and the latter gets strenuously cured. Quite often it’s not the point, anyway. It should be admitted that 504 Gateway Timeout happens when nginx sends client Apache requests but Apache fails to return HTTP-response within the established limit of time. I am getting 504 timeouts message from nginx when my PHP script is running longer than usual Does it not work when running php5-fpm on nginx? If so, whats the proper way of setting the time limit?
Edhesive in
504 Gateway Timeout Select your preferred language English (US) Deutsch Español Français 日本語 한국어 Português (do Brasil) Português (Europeu) Русский 中文 (简体) 正體中文 (繁體) Change language
504 gateway time-out nginx nodejs 504 gateway time-out nginx docker 504 gateway time-out nginx mulesoft 504 gateway timeout nginx aws 504 gateway time-out php nginx 504 gateway timeout localhost nginx bad gateway timeout 504 gateway time-out nginx/1.4 6
Dj basti in
May 09, 2017 · # service nginx restart nginx: [emerg] «location» directive is not allowed here in /etc/nginx/nginx.conf:34 nginx: configuration file /etc/nginx/nginx.conf test failed You can only use the location modifiers that is allowed by nginx (for example: =). In the following snippet, we are using $ as location modifier which is not allowed by Nginx.
Nginx issues the XOIP command to the upstream POP3 server, and the ID command to the upstream IMAP server, before logging in to upstream. This is for auditing purposes so that the client’s IP address is known to the upstream server.
Battery pack making high pitched noise
Tall plants
The law of increasing costs indicates that the opportunity cost of producing a good_
Cavallo mischief trailer
Cor thermostat keeps disconnecting from wifi
Ps5 vs xbox series x specs comparison chart
Asr flash hider length
in /etc/nginx.conf (or /etc/nginx/nginx.conf some reddit threads say its in /usr/local/etc/nginx) or its parts included from main file ( with include /path/to/file directive ) You have to restart nginx after changing its config. (with nginx -s reload or via your OS services controller)
Sep 18, 2016 · (Solucionado) 504 Gateway Time-out nginx al importar productos PS 1.6.0.9 By Beicker , September 18, 2016 in PrestaShop Download: instalación, actualización y configuración Recommended Posts
Mar 23, 2018 · For Nginx as Proxy for Apache web server, this is what you have to try to fix the 504 Gateway Timeout error: Add these variables to nginx.conf file: proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600; send_timeout 600; Then restart nginx: service nginx reload Additional Resources. HTTP Status Codes on W3C; Popular search …
Dec 21, 2020 · 504 Gateway Time-out nginx. Re: 504 Gateway Time-out nginx. Teaching with Moodle. Moodle research. Usability. Comparisons and advocacy. Hardware and performance. Security and privacy. MoodleCloud. MoodleNet. Lounge. Glossary of common terms. Activities. Other components. Moodle development
Sep 30, 2014 · nginx/1.0.15 Please suggest. Thanks and Regards, Gangadhar kadam. Timeout values can be increased by passing “-t number_of_seconds” to gunicorn and setting proxy_read_timeout in nginx config. For the rest, I’ve sent a personal email to you. – Note: If you are posting an issue, We should be able to replicate it at our end. So please give …
Hornady 35 gr ntx 22 250
Speer lawman 380 ammo
Surface book 2 2004 update
Highest score in brainium solitaire
Gps maps free
Onteora speedway
Huhu.to alternative
How to make a submarine float sink float without touching it
How to change location on google chrome
Doordash state employer payroll number
Sig sauer p365 15 round magazine disassembly
6.4 powerstroke egr delete pros and cons
C3h5 valence electrons
232cc gy6 top speed
Easy to draw scary monsters
Athearn parts diagrams
Draconic evolution mob grinder mob souls
What time does walmart open on black friday in massachusetts
Bernardelli italy
Gentoo based distro
G35 rear differential upgrade
Acer one 10 windows 10 install
Just build 1v1
N95 8210 mask malaysia
Custom canvas tarps near me
Craigslist midland
Lowrance transducer mounting instructions
Fatal truck crash videos
Wow garrison bfa
5e remove fear
Maytag maxima diagnostic mode
Android emulator docker container
Stripped down pontoon boat for sale
Ryzen 5 3600 enable virtualization
Saddest goodbye letter to girlfriend
Типичный сеанс HTTP — HTTP
В протоколах клиент-сервер, таких как HTTP, сеансы состоят из трех фаз:
- Клиент устанавливает TCP-соединение (или соответствующее соединение, если транспортный уровень не является TCP).
- Клиент отправляет свой запрос и ждет ответа.
- Сервер обрабатывает запрос, отправляя ответ, предоставляя код состояния и соответствующие данные.
Начиная с HTTP / 1.1, соединение больше не закрывается после завершения третьей фазы, и теперь клиенту предоставляется дополнительный запрос: это означает, что вторая и третья фазы теперь могут выполняться любое количество раз.
В протоколах клиент-сервер соединение устанавливает клиент. Открытие соединения в HTTP означает инициирование соединения на нижележащем транспортном уровне, обычно это TCP.
С TCP портом по умолчанию для HTTP-сервера на компьютере является порт 80. Могут использоваться и другие порты, например 8000 или 8080. URL-адрес страницы для выборки содержит как имя домена, так и номер порта, хотя последнее можно не указывать, если оно равно 80. Для получения более подробной информации см. Определение ресурсов в Интернете.
Примечание
Модель клиент-сервер не позволяет серверу отправлять данные клиенту без явного запроса на это. Чтобы обойти эту проблему, веб-разработчики используют несколько методов: периодически проверять связь с сервером через XMLHTTPRequest
, WindowOrWorkerGlobalScope.fetch
API, используя WebSockets API или аналогичные протоколы.
Как только соединение установлено, пользовательский агент может отправить запрос (пользовательский агент обычно является веб-браузером, но может быть любым другим, например, поисковым роботом).Клиентский запрос состоит из текстовых директив, разделенных CRLF (возврат каретки, за которым следует перевод строки), разделенных на три блока:
- Первая строка содержит метод запроса, за которым следуют его параметры:
- путь к документу, то есть абсолютный URL без протокола или имени домена
- версия протокола HTTP
- Последующие строки представляют заголовок HTTP, дающий серверу информацию о том, какой тип данных подходит (например,g., какой язык, какие типы MIME) или другие данные, изменяющие его поведение (например, не отправка ответа, если он уже кэширован). Эти заголовки HTTP образуют блок, который заканчивается пустой строкой.
- Последний блок — это необязательный блок данных, который может содержать дополнительные данные, в основном используемые методом POST.
Примеры запросов
Получение корневой страницы developer.mozilla.org, то есть https://developer.mozilla.org/, и сообщение серверу, что пользовательский агент предпочел бы страницу на французском языке, если это возможно:
GET / HTTP / 1.1 Хост: developer.mozilla.org Принять-Язык: fr
Обратите внимание на последнюю пустую строку, она отделяет блок данных от блока заголовка. Поскольку в заголовке HTTP отсутствует Content-Length
, этот блок данных представляется пустым, отмечая конец заголовков, что позволяет серверу обрабатывать запрос в момент получения этой пустой строки.
Например, отправка результата формы:
POST /contact_form.php HTTP / 1.1 Хост: developer.mozilla.org Длина содержимого: 64 Тип содержимого: application / x-www-form-urlencoded name = Joe% 20User & request = Отправить% 20me% 20one% 20of% 20your% 20catalogue
Методы запроса
HTTP определяет набор методов запроса, указывающих желаемое действие, которое должно быть выполнено над ресурсом. Хотя они также могут быть существительными, эти методы запросов иногда называют HTTP-глаголами. Наиболее частые запросы: GET
и POST
:
.
- Метод
GET
запрашивает представление данных указанного ресурса.Запросы, использующиеGET
, должны только получать данные. - Метод
POST
отправляет данные на сервер, чтобы он мог изменить свое состояние. Этот метод часто используется для HTML-форм.
После того, как подключенный агент отправил свой запрос, веб-сервер обрабатывает его и в конечном итоге возвращает ответ. Подобно клиентскому запросу, ответ сервера состоит из текстовых директив, разделенных CRLF, но разделенных на три блока:
- Первая строка, строка состояния , состоит из подтверждения используемой версии HTTP, за которым следует запрос состояния (и его краткое значение в удобочитаемом тексте).
- Последующие строки представляют определенные заголовки HTTP, дающие клиенту информацию об отправленных данных (например, тип, размер данных, используемый алгоритм сжатия, подсказки о кэшировании). Подобно блоку заголовков HTTP для запроса клиента, эти заголовки HTTP образуют блок, заканчивающийся пустой строкой.
- Последний блок — это блок данных, который содержит необязательные данные.
Примеры ответов
Успешный ответ веб-страницы:
HTTP / 1.1 200 ОК Тип содержимого: текст / html; charset = utf-8 Длина содержимого: 55743 Подключение: keep-alive Cache-Control: s-maxage = 300, общедоступный, max-age = 0 Content-Language: en-US Дата: чт, 06 дек.2018 г., 17:37:18 GMT ETag: "2e77ad1dc6ab0b53a2996dfd4653c1c3" Сервер: meinheld / 0.6.1 Строгая транспортная безопасность: max-age = 63072000 Параметры X-Content-Type: nosniff Параметры X-Frame: ОТКАЗАТЬ X-XSS-Protection: 1; режим = блок Варьируется: кодировка принятия, cookie Возраст: 7Простая веб-страница Простая веб-страница HTML5
Привет, мир!
Уведомление о том, что запрошенный ресурс окончательно перемещен:
HTTP / 1.1 301 перемещен навсегда Сервер: Apache / 2.4.37 (Red Hat) Тип содержимого: текст / html; charset = utf-8 Дата: четверг, 06 декабря 2018 г., 17:33:08 GMT Расположение: https://developer.mozilla.org/ (это новая ссылка на ресурс; ожидается, что пользовательский агент получит ее) Keep-Alive: тайм-аут = 15, максимум = 98 Accept-Ranges: байты Через: Moz-Cache-zlb05 Подключение: Keep-Alive Content-Length: 325 ( контент содержит страницу по умолчанию для отображения, если пользовательский агент не может перейти по ссылке) (содержит настроенную для сайта страницу, помогающую пользователю найти недостающий ресурс)
Уведомление о том, что запрошенный ресурс не существует:
HTTP / 1.1 404 Не найдено Тип содержимого: текст / html; charset = utf-8 Длина содержимого: 38217 Подключение: keep-alive Cache-Control: no-cache, no-store, must-revalidate, max-age = 0. Content-Language: en-US Дата: четверг, 06 декабря 2018 г., 17:35:13 GMT Истекает: Thu, 06 Dec 2018 17:35:13 GMT Сервер: meinheld / 0.6.1 Строгая транспортная безопасность: max-age = 63072000 Параметры X-Content-Type: nosniff Параметры X-Frame: ОТКАЗАТЬ X-XSS-Protection: 1; режим = блок Варьируется: кодировка принятия, cookie X-Cache: ошибка из облачного интерфейса (содержит настроенную для сайта страницу, помогающую пользователю найти недостающий ресурс)
Коды состояния ответа
Коды состояния ответа HTTP указывают, был ли успешно выполнен конкретный запрос HTTP. Ответы сгруппированы в пять классов: информационные ответы, успешные ответы, перенаправления, ошибки клиента и ошибки серверов.
-
200
: ОК. Запрос выполнен. -
301
: перемещен навсегда.Этот код ответа означает, что URI запрошенного ресурса был изменен. -
404
: Не найдено. Сервер не может найти запрошенный ресурс.
HTTP / 1.1: соединения
HTTP / 1.1: соединения
часть протокола передачи гипертекста — HTTP / 1.1RFC 2616 Fielding, et al.
8 подключений
8.1 Постоянные соединения
8.1.1 Назначение
До постоянных подключений отдельное TCP-подключение было
установлен для получения каждого URL, увеличивая нагрузку на HTTP-серверы
и вызывая перегрузку в Интернете.Использование встроенных изображений и
другие связанные данные часто требуют, чтобы клиент сделал несколько
запросы одного и того же сервера за короткий промежуток времени. Анализ
эти проблемы с производительностью и результаты прототипа
реализации доступны [26] [30]. Опыт внедрения и
измерения реальных реализаций HTTP / 1.1 (RFC 2068) показывают хорошие
результаты [39]. Также были изучены альтернативы, например,
T / TCP [27].
Постоянные HTTP-соединения имеют ряд преимуществ:
- За счет открытия и закрытия меньшего количества TCP-соединений экономится время ЦП. в маршрутизаторах и хостах (клиенты, серверы, прокси, шлюзы, туннели или кеши) и память, используемая для управления протоколом TCP блоки можно сохранять в hosts.
- HTTP-запросы и ответы могут быть конвейеризованы для соединения. Конвейерная обработка позволяет клиенту делать несколько запросов без ожидая каждого ответа, разрешая одно TCP-соединение с можно использовать гораздо более эффективно, с гораздо меньшим затраченным временем.
- Перегрузка сети снижается за счет уменьшения количества пакетов вызвано открытием TCP и предоставлением TCP достаточного времени для определить состояние перегрузки сети.
- Задержка при последующих запросах уменьшена, так как нет времени потрачено на рукопожатие открытия TCP-соединения.
- HTTP может развиваться более изящно, поскольку можно сообщать об ошибках без штрафа за закрытие TCP-соединения. Клиенты, использующие будущие версии HTTP могут оптимистично попробовать новую функцию, но если вы обмениваетесь данными со старым сервером, повторите попытку со старым семантика после сообщения об ошибке.
Реализации HTTP ДОЛЖНЫ реализовывать постоянные соединения.
8.1.2 Общая работа
Существенная разница между HTTP / 1.1 и более ранними версиями
HTTP заключается в том, что постоянные соединения являются поведением по умолчанию любого
HTTP-соединение. То есть, если не указано иное, клиент
СЛЕДУЕТ предполагать, что сервер будет поддерживать постоянное соединение,
даже после сообщений об ошибках от сервера.
Постоянные соединения обеспечивают механизм, с помощью которого клиент и
сервер может сигнализировать о закрытии TCP-соединения.Эта сигнализация занимает
разместите, используя поле заголовка соединения (раздел 14.10). После закрытия
был сигнализирован, клиент НЕ ДОЛЖЕН отправлять больше запросов на этом
связь.
8.1.2.1 Согласование
Сервер HTTP / 1.1 МОЖЕТ предполагать, что клиент HTTP / 1.1 намеревается
поддерживать постоянное соединение, если заголовок соединения не включает
в запросе был отправлен токен соединения «закрыть». Если сервер
решает закрыть соединение сразу после отправки
ответ, он ДОЛЖЕН отправить заголовок соединения, включая
токен подключения закрыть.
Клиент HTTP / 1.1 МОЖЕТ ожидать, что соединение останется открытым, но будет
решите оставить его открытым в зависимости от того, будет ли ответ от сервера
содержит заголовок соединения с закрытым токеном соединения. В случае
клиент не хочет поддерживать соединение больше, чем это
запрос, он ДОЛЖЕН отправить заголовок соединения, включая
токен подключения закрыть.
Если клиент или сервер отправляет токен закрытия в
Заголовок соединения, этот запрос становится последним для
связь.
Клиентам и серверам НЕ СЛЕДУЕТ предполагать, что постоянное соединение
поддерживается для версий HTTP ниже 1.1, если это не указано явно
сигнализировал. См. Раздел 19.6.2 для получения дополнительной информации об обратном
совместимость с клиентами HTTP / 1.0.
Чтобы оставаться постоянными, все сообщения в соединении ДОЛЖНЫ
иметь самоопределяемую длину сообщения (т. е. не определенную закрытием
соединения), как описано в разделе 4.4.
8.1.2.2 Трубопровод
Клиент, поддерживающий постоянные соединения, МОЖЕТ «конвейерно»
запросов (т.е. отправлять несколько запросов, не дожидаясь каждого
отклик). Сервер ДОЛЖЕН отправлять свои ответы на эти запросы в
в том же порядке, в котором были получены запросы.
Клиенты, которые предполагают постоянные соединения и конвейер немедленно
после установления соединения СЛЕДУЕТ быть готовым к повторной попытке
соединение, если первая конвейерная попытка не удалась.Если клиент
такая повторная попытка НЕ ДОЛЖНА быть конвейерной, пока не узнает, что соединение
настойчивый. Клиенты ДОЛЖНЫ быть готовы повторно отправить свои запросы, если
сервер закрывает соединение перед отправкой всех
соответствующие ответы.
Клиентам НЕ СЛЕДУЕТ конвейерные запросы с использованием неидемпотентных методов или
неидемпотентные последовательности методов (см. раздел 9.1.2). В противном случае
преждевременное прекращение транспортного сообщения могло привести к
неопределенные результаты.Клиент, желающий отправить неидемпотентный
request СЛЕДУЕТ подождать отправки этого запроса, пока он не получит
статус ответа на предыдущий запрос.
8.1.3 Прокси-серверы
Особенно важно, чтобы прокси правильно реализовали
свойства поля заголовка соединения, как указано в разделе
14.10.
Прокси-сервер ДОЛЖЕН сигнализировать о постоянных соединениях отдельно с помощью
своих клиентов и исходных серверов (или других прокси-серверов), которые он
подключается к.Каждое постоянное соединение применяется только к одному транспорту
связь.
Прокси-сервер НЕ ДОЛЖЕН устанавливать постоянное соединение HTTP / 1.1.
с клиентом HTTP / 1.0 (но см. RFC 2068 [33] для информации и
обсуждение проблем с заголовком Keep-Alive, реализованных
многие клиенты HTTP / 1.0).
8.1.4 Практические соображения
Серверы обычно имеют некоторое значение тайм-аута, по истечении которого они будут
больше не поддерживать неактивное соединение.Прокси-серверы могут сделать
это более высокое значение, поскольку вполне вероятно, что клиент будет делать
больше подключений через один и тот же сервер. Использование стойких
соединений не предъявляет требований к длине (или наличию)
этот тайм-аут либо для клиента, либо для сервера.
Когда клиент или сервер желает истечь тайм-аут, он ДОЛЖЕН выдать изящный
Рядом транспортное сообщение. Клиенты и серверы ДОЛЖНЫ
постоянно следите за тем, чтобы другая сторона транспорта не приближалась, и
ответьте на него соответствующим образом.Если клиент или сервер не обнаруживает
быстрое закрытие другой стороны может вызвать ненужный ресурс
сток в сети.
Клиент, сервер или прокси МОГУТ закрыть транспортное соединение в любой момент.
время. Например, клиент мог начать отправлять новый запрос.
при этом сервер решил закрыть «холостой»
связь. С точки зрения сервера, соединение
закрывается, пока он простаивает, но с точки зрения клиента
запрос выполняется.
Это означает, что клиенты, серверы и прокси ДОЛЖНЫ иметь возможность восстанавливать
от асинхронных событий закрытия. Клиентское программное обеспечение ДОЛЖНО снова открыть
транспортное соединение и ретранслировать прерванную последовательность запросов
без взаимодействия с пользователем, пока последовательность запроса
идемпотентный (см. раздел 9.1.2). Неидемпотентные методы или последовательности
НЕ ДОЛЖЕН повторяться автоматически, хотя пользовательские агенты МОГУТ предлагать
человек-оператор выбор повторной попытки запроса (ов).Подтверждение
ПО user-agent с семантическим пониманием приложения
МОЖЕТ заменить подтверждение пользователя. Автоматическая повторная попытка НЕ ДОЛЖНА
повторяться, если вторая последовательность запросов не удалась.
Серверы ДОЛЖНЫ всегда отвечать хотя бы на один запрос на каждое соединение,
если вообще возможно. Серверам НЕ СЛЕДУЕТ закрывать соединение в
середина передачи ответа, кроме сбоя сети или клиента
подозревается.
Клиентам, использующим постоянные соединения, СЛЕДУЕТ ограничить количество
одновременные соединения, которые они поддерживают с заданным сервером.А
однопользовательский клиент НЕ ДОЛЖЕН поддерживать более 2 соединений с
любой сервер или прокси. Прокси-сервер ДОЛЖЕН использовать до 2 * N подключений к
другой сервер или прокси, где N — количество одновременно
активные пользователи. Эти рекомендации предназначены для улучшения HTTP-ответа.
раз и избежать заторов.
8.2 Требования к передаче сообщений
8.2.1 Постоянные соединения и управление потоком
Серверы HTTP / 1.1 ДОЛЖНЫ поддерживать постоянные соединения и использовать TCP
механизмы управления потоком для устранения временных перегрузок, а не
завершение соединений с ожиданием повторной попытки клиентов.Последний метод может усугубить перегрузку сети.
8.2.2 Мониторинг подключений для сообщений об ошибках
Клиент HTTP / 1.1 (или новее), отправляющий тело сообщения, ДОЛЖЕН отслеживать
сетевое соединение для статуса ошибки во время передачи
запрос. Если клиент видит статус ошибки, он ДОЛЖЕН
немедленно прекратите передавать тело. Если тело отправляется
используя «фрагментированное» кодирование (раздел 3.6), фрагмент нулевой длины и
пустой трейлер МОЖЕТ использоваться для преждевременной отметки конца сообщения.Если телу предшествовал заголовок Content-Length, клиент ДОЛЖЕН
закрыть соединение.
8.2.3 Использование статуса 100 (Продолжить)
Статус 100 (Продолжить) (см. Раздел 10.1.1) предназначен для
разрешить клиенту, который отправляет сообщение запроса с телом запроса
чтобы определить, готов ли исходный сервер принять запрос
(на основе заголовков запроса) до того, как клиент отправит запрос
тело. В некоторых случаях это может быть либо неуместным, либо крайне неуместным.
неэффективно для клиента отправить тело, если сервер отклонит
сообщение, не глядя на тело.
Требования к клиентам HTTP / 1.1:
- Если клиент будет ждать ответа 100 (Продолжить) до отправляя тело запроса, он ДОЛЖЕН отправить заголовок запроса Expect поле (раздел 14.20) с ожиданием «100-continue».
- Клиент НЕ ДОЛЖЕН отправлять поле заголовка запроса Expect (раздел 14.20) с ожиданием «100-continue», если он не намерен отправить тело запроса.
Из-за наличия более старых реализаций протокол позволяет
неоднозначные ситуации, в которых клиент может отправить «Ожидайте: 100-
продолжить «без получения статуса 417 (ожидание не выполнено)
или статус 100 (Продолжить). Следовательно, когда клиент отправляет это
поле заголовка на исходный сервер (возможно, через прокси), с которого он
никогда не видел статуса 100 (Продолжить), клиент НЕ ДОЛЖЕН ждать
на неопределенный срок перед отправкой тела запроса.
Требования к исходным серверам HTTP / 1.1:
- После получения запроса, который включает заголовок запроса Expect. поле с ожиданием «100-continue», исходный сервер ДОЛЖЕН либо ответьте со статусом 100 (Продолжить) и продолжайте читать из входного потока или ответьте окончательным кодом состояния. В исходный сервер НЕ ДОЛЖЕН ждать тела запроса перед отправкой ответ 100 (Продолжить).Если он отвечает с окончательным статусом код, он МОЖЕТ закрыть транспортное соединение или МОЖЕТ продолжить
, чтобы прочитать и отклонить остальную часть запроса. НЕ ДОЛЖЕН выполнить запрошенный метод, если он возвращает окончательный код состояния.
- Исходный сервер НЕ ДОЛЖЕН отправлять ответ 100 (Продолжить), если сообщение запроса не включает заголовок запроса Expect поле с ожиданием «100-continue» и НЕ ДОЛЖЕН отправлять 100 (Продолжить) ответ, если такой запрос исходит от HTTP / 1.0 (или более ранний) клиент. Есть исключение из этого правила: для совместимость с RFC 2068, сервер МОЖЕТ отправить 100 (Продолжить) статус в ответ на запрос HTTP / 1.1 PUT или POST, который не включать поле заголовка запроса Expect с "100- продолжить "ожидание. Это исключение, цель которого чтобы свести к минимуму любые задержки обработки клиентов, связанные с необъявленное ожидание статуса 100 (Продолжить), применяется только к HTTP / 1.1, а не на запросы с любыми другими HTTP- значение версии.
- Исходный сервер МОЖЕТ пропустить ответ 100 (Продолжить), если он уже получил часть или все тело запроса для соответствующий запрос.
- Исходный сервер, который отправляет ответ 100 (Продолжить), ДОЛЖЕН в конечном итоге отправить окончательный код состояния, как только тело запроса получены и обработаны, если это не прекращает транспортировку подключение преждевременно.
- Если исходный сервер получает запрос, не содержащий Ожидайте поле заголовка запроса с ожиданием "100-continue", запрос включает тело запроса, и сервер отвечает с окончательным кодом состояния перед чтением всего тела запроса из транспортного соединения, то серверу НЕ СЛЕДУЕТ закрывать транспортное соединение, пока не будет прочитан весь запрос, или пока клиент не закроет соединение.В противном случае клиент может ненадежно получить ответное сообщение. Однако это требование не должно толковаться как препятствие серверу защищаясь от атак типа "отказ в обслуживании" или от сильно сломанные клиентские реализации.
Требования к прокси HTTP / 1.1:
- Если прокси получает запрос, который включает запрос ожидания - поле заголовка с ожиданием "100-continue" и прокси либо знает, что сервер следующего перехода соответствует HTTP / 1.1 или выше или не знает HTTP-версию следующего перехода сервер, он ДОЛЖЕН пересылать запрос, включая заголовок Expect. поле.
- Если прокси-сервер знает, что версия сервера следующего перехода HTTP / 1.0 или ниже, он НЕ ДОЛЖЕН пересылать запрос и ДОЛЖЕН ответьте статусом 417 (ожидание не выполнено).
- Прокси-серверы ДОЛЖНЫ поддерживать кеш-запись версии HTTP. числа, полученные от серверов следующего перехода, на которые недавно ссылались.
- Прокси-сервер НЕ ДОЛЖЕН пересылать ответ 100 (Продолжить), если сообщение с запросом было получено от HTTP / 1.0 (или более ранней версии) клиент и не включал поле заголовка запроса Expect с ожидание «100-продолжения». Это требование отменяет общее правило пересылки ответов 1xx (см. раздел 10.1).
8.2.4 Поведение клиента, если сервер преждевременно закрывает соединение
Если HTTP / 1.1 клиент отправляет запрос, который включает тело запроса,
но который не включает поле заголовка запроса Expect с
Ожидание «100-продолжения», и если клиент напрямую не
подключен к исходному серверу HTTP / 1.1, и если клиент видит
соединение закрывается до получения какого-либо статуса от сервера,
клиент ДОЛЖЕН повторить запрос. Если клиент все же попытается это сделать
запрос, он МОЖЕТ использовать следующую «двоичную экспоненциальную отсрочку»
алгоритм, чтобы быть уверенным в получении надежного ответа:
1.Инициировать новое подключение к серверу
2. Передать заголовки запроса.
3. Инициализируйте переменную R равным расчетному времени приема-передачи сервер (например, в зависимости от времени, которое потребовалось для установки соединение), или на постоянное значение 5 секунд, если раунд- время поездки недоступно.
4. Вычислить T = R * (2 ** N), где N - количество предыдущих повторные попытки этого запроса.
5. Дождитесь либо сообщения об ошибке от сервера, либо T секунды (в зависимости от того, что наступит раньше)
6. Если сообщение об ошибке не получено, через T секунд передайте сообщение тело запроса.
7. Если клиент видит, что соединение преждевременно закрыто, повторять с шага 1 до тех пор, пока запрос не будет принят, ошибка получен ответ, или пользователь становится нетерпеливым и завершает процесс повтора.
Если в какой-то момент получен статус ошибки, клиент
- НЕ ДОЛЖЕН продолжать и
- СЛЕДУЕТ закрыть соединение, если оно не завершило отправку сообщение-запрос.
Создание приложений реального времени с помощью веб-сокетов и событий, отправляемых сервером
Эта статья была рецензирована Крейгом Билнером и Дэном Принсом. Спасибо всем рецензентам SitePoint за то, что они сделали контент SitePoint как можно лучше!
Важной частью написания многофункциональных интернет-приложений является реакция на изменения данных.Рассмотрим следующую цитату Гильермо Рауха, взятую из его выступления на BrazilJS в 2014 году «7 принципов создания полнофункциональных веб-приложений».
Если данные на сервере изменяются, сообщите об этом клиентам, не спрашивая. Это форма повышения производительности, которая освобождает пользователя от действий по обновлению вручную (F5, потяните, чтобы обновить). Новые задачи: (повторное) управление подключением, согласование состояний.
В этой статье мы рассмотрим примеры использования необработанного API WebSocket, а также менее известного EventSource для событий, отправляемых сервером (SSE), для создания самообновляющихся пользовательских интерфейсов в реальном времени.Если вы не понимаете, что я имею в виду, рекомендую посмотреть видео, указанное выше, или прочитать соответствующее сообщение в блоге.
Краткая история
Раньше нам приходилось моделировать server-push, наиболее известным методом был длинный опрос. При этом клиент делал длинный запрос, который оставался открытым до тех пор, пока сервер не был готов отправить сообщение. После получения сообщения запрос будет закрыт, и будет сделан новый запрос. Другие решения включали
хаков и Flash.Это было не идеально.
Затем, в 2006 году, Opera представила события отправки сервером (SSE) из спецификации WHATWG Web Applications 1.0.
SSE позволял вам непрерывно передавать события с вашего веб-сервера в браузер посетителя. Другие браузеры последовали их примеру и начали внедрять SSE в 2011 году как часть спецификации HTML5.
В 2011 году, когда протокол WebSocket был стандартизован, все продолжало быть интересным. WebSockets позволяет вам открывать двустороннее постоянное соединение между клиентом и сервером, давая вам возможность отправлять данные обратно клиентам всякий раз, когда данные изменяются на сервере, без необходимости запрашивать их у клиента.Это чрезвычайно важно для быстрого реагирования приложения с большим количеством одновременных подключений и быстро меняющимся содержимым — например, многопользовательской онлайн-игры. Однако только в 2014 году, когда в 2014 году был выпущен socket.io — наиболее заметная попытка довести WebSockets до масс, — мы увидели гораздо больше экспериментов с общением в реальном времени.
Достаточно сказать, что сегодня у нас есть гораздо более простые способы достижения server-push без выдачи новых запросов или использования нестандартных плагинов.Эти технологии дают вам возможность передавать данные обратно клиенту в тот момент, когда что-то происходит на сервере.
Веб-сокеты
Самый простой способ понять, что позволяет постоянное соединение, — это запустить рабочую демонстрацию. Мы рассмотрим код позже, а пока скачайте демоверсию и поиграйте.
Демо
git clone https://github.com/sitepoint-editors/websocket-demo.git
cd websocket-demo
npm install
npm start
Откройте http: // localhost: 8080 / в нескольких окнах браузера и просмотрите журналы как в браузере, так и на сервере, чтобы увидеть сообщения, отправляемые туда и обратно.Что еще более важно, обратите внимание на время, необходимое для получения сообщения на сервере и для остальных подключенных клиентов, чтобы узнать об изменении.
Клиент
Конструктор WebSocket
инициирует соединение с сервером по протоколам ws
или wss
(Secure). Он имеет метод send
для отправки данных на сервер, и вы можете предоставить обработчик onmessage
для получения данных с сервера.
Вот аннотированный пример, показывающий все важные события:
var socket = new WebSocket ('ws: // localhost: 8081 /');
разъем.onopen = function () {
console.log ('Открытое соединение 🎉');
var json = JSON.stringify ({сообщение: 'Привет 👋'});
socket.send (json);
}
socket.onmessage = function (событие) {
console.log (event.data);
}
socket.onerror = function (событие) {
console.log (событие);
}
socket.onclose = function (код, причина) {
console.log (код, причина);
}
window.addEventListener ('beforeunload', function () {
socket.close ();
});
Сервер
Самая популярная библиотека Node для работы с WebSockets на сервере — это ws, мы будем использовать ее для упрощения, поскольку написание серверов WebSocket — нетривиальная задача.
var WSS = require ('ws'). Server;
var wss = новый WSS ({порт: 8081});
wss.on ('соединение', функция (сокет) {
console.log ('Открытое соединение 🎉');
var json = JSON.stringify ({message: 'Gotcha'});
socket.send (json);
socket.on ('сообщение', функция (сообщение) {
console.log ('Получено:' + сообщение);
});
socket.on ('закрыть', function () {
console.log («Закрытое соединение 😱»);
});
});
var broadcast = function () {
var json = JSON.stringify ({
сообщение: "Привет, привет!"
});
wss.client.forEach (функция each (client) {
client.send (json);
console.log ('Отправлено:' + json);
});
}
setInterval (трансляция, 3000);
Пакет ws
упрощает создание сервера с поддержкой WebSocket, однако вам следует ознакомиться с WebSocket Security, если вы используете их в производственной среде.
Совместимость с браузером
Браузер поддерживает WebSockets надежно, за исключением Opera Mini и IE9 и более ранних версий, для старых IE есть полифил, который негласно использует Flash.
Могу ли я использовать WebSockets? Данные о поддержке функций веб-сокетов в основных браузерах с сайта caniuse.com.
Отладка
В Chrome вы можете проверить отправленные и полученные сообщения в разделе «Сеть»> «WS»> «Фреймы», отправленные сообщения отображаются зеленым цветом.
Отладка
WebSocket в Firefox возможна с помощью надстройки Websocket Monitor для Firefox Dev Tools. Он разработан командой разработчиков Firebug.
События, отправленные сервером
Как и WebSockets, SSE открывает постоянное соединение, которое позволяет отправлять данные обратно подключенным клиентам при втором изменении на сервере.Единственное предостережение: он не позволяет сообщениям идти в обратном направлении. Это не проблема, у нас все еще есть старые добрые методы Ajax для этого.
Демо
git clone https://github.com/sitepoint-editors/server-sent-events-demo.git
CD-сервер-отправлено-события-демонстрация
npm install
npm start
Как и раньше, откройте http: // localhost: 8080 / в нескольких окнах браузера и просмотрите журналы как в браузере, так и на сервере, чтобы увидеть сообщения, идущие туда и обратно.
Клиент
Функция EventSource
инициирует соединение с сервером через старый добрый HTTP или HTTPS. Он имеет API-интерфейс, аналогичный WebSocket
, и вы можете предоставить обработчик onmessage
для получения данных с сервера. Вот аннотированный пример, показывающий все важные события.
var stream = new EventSource ("/ sse");
stream.onopen = function () {
console.log ('Открытое соединение 🎉');
};
stream.onerror = function (event) {
консоль.журнал (событие);
};
stream.onmessage = function (event) {
console.log (event.data);
};
stream.onclose = function (код, причина) {
console.log (код, причина);
}
window.addEventListener ('beforeunload', function () {
stream.close ();
});
Сервер
Есть небольшая изящная оболочка sse для создания событий, отправляемых сервером. Сначала мы воспользуемся этим, чтобы упростить задачу, но отправить события с сервера достаточно просто, , чтобы сделать это самостоятельно, поэтому мы объясним, как работает SSE на сервере позже.
var SSE = require ('sse');
var http = require ('http');
var server = http.createServer ();
var клиенты = [];
server.listen (8080, '127.0.0.1', function () {
var sse = новый SSE (сервер);
sse.on ('соединение', функция (поток) {
console.log ('Открытое соединение 🎉');
client.push (поток);
var json = JSON.stringify ({message: 'Gotcha'});
stream.send (json);
console.log ('Отправлено:' + json);
stream.on ('закрыть', function () {
client.splice (клиенты.indexOf (поток), 1);
console.log ('Закрытое соединение 😱');
});
});
});
var broadcast = function () {
var json = JSON.stringify ({сообщение: 'Привет, привет!'});
client.forEach (функция (поток) {
stream.send (json);
console.log ('Отправлено:' + json);
});
}
setInterval (трансляция, 3000)
Отправка событий с сервера
Как упоминалось выше, отправка событий с сервера достаточно проста, чтобы сделать это сами. Вот как это сделать:
Когда HTTP-запрос поступает из EventSource
, он будет иметь заголовок Accept
из text / event-stream
, нам нужно ответить заголовками, которые поддерживают HTTP-соединение, а затем, когда мы будем готовы отправить данные обратно клиенту мы записываем данные в объект Response
в специальном формате data: \ n \ n
.
http.createServer (function (req, res) {
res.writeHead (200, {
'Content-Type': 'текст / поток событий',
'Cache-Control': 'без кеширования',
'Connection': 'keep-alive'
});
var json = JSON.stringify ({сообщение: 'Привет 👋'});
res.write ("данные:" + json + "\ n \ n");
}). listen (8000);
В дополнение к полю данных
вы также можете отправить поля события, идентификатора и повтора, если они вам нужны, например
событие: SOMETHING_HAPPENED
данные: вещь
id: 123
повтор: 300
событие: SOMETHING_ELSE_HAPPENED
данные: вещь
id: 124
повтор: 300
Хотя SSE удивительно просто реализовать как на клиенте, так и на сервере, как упоминалось выше, его единственное предостережение заключается в том, что он не предоставляет способ отправки данных с клиента на сервер.К счастью, мы уже можем сделать это с помощью XMLHttpRequest
или fetch
. Наша новая открытая сверхспособность — это возможность передавать данные от сервера к клиенту.
В целях безопасности, поскольку это HTTP, применяются стандартные правила кросс-происхождения, поэтому вы всегда должны вносить источники в белый список как на сервере, так и на клиенте:
stream.onmessage = function (event) {
если (e.origin! = 'http://example.com') return;
}
Затем мы все еще можем отправить на сервер, как обычно, с помощью старого доброго Ajax:
документ.querySelector ('# send'). addEventListener ('щелчок', функция (событие) {
var json = JSON.stringify ({message: 'Привет!'});
var xhr = новый XMLHttpRequest ();
xhr.open ('POST', '/ api', истина);
xhr.setRequestHeader ('Content-Type', 'application / json');
xhr.send (json);
журнал ('Отправлено:' + json);
});
Совместимость с браузером
Браузер поддерживает SSE ниже, чем WebSocket, потому что Microsoft никогда не поставляла браузер, который его поддерживает, для него есть отчет об ошибке, и вы все должны проголосовать за SSE, чтобы сделать его приоритетом для следующего выпуска.
Могу ли я использовать WebSockets? Данные о поддержке функций веб-сокетов в основных браузерах с сайта caniuse.com.
Если вам нужно заставить SSE работать в IE и Edge сегодня, вы можете использовать Polyfill для EventSource.
Отладка
В Chrome вы можете проверять полученные сообщения в разделе Сеть> XHR> EventStream
Вызовы
В статье Гильермо Рауха, цитируемой в начале, (повторное) управление подключением и согласование состояний упоминаются как новых проблем, которые возникли в результате этих постоянных подключений.Он прав, вам нужно подумать о том, что должно произойти, когда соединение потеряно и когда оно будет восстановлено.
EventSource
имеет встроенный механизм повторного подключения, он будет пытаться повторно подключиться каждые 3 секунды, если соединение будет потеряно автоматически. Вы можете проверить это в демонстрации SSE, установив соединение в браузере и остановив сервер с помощью Ctrl + C , вы увидите ошибки, которые регистрируются до тех пор, пока вы снова не запустите сервер резервное копирование с npm start
, он сохраняет спокойствие и продолжает.
WebSocket
не имеет этой возможности, если соединение потеряно, вам нужно будет создать новое и снова подключить события, если вы хотите того же поведения.
Согласование состояний — это практика синхронизации клиента с сервером при повторном подключении. Один из способов сделать это — отслеживать время, когда произошло отключение, и при повторном подключении отправлять все события, которые конкретный клиент пропустил во время отключения.
Решения этих проблем различаются в зависимости от типа приложения, которое вы создаете:
- Если вы создаете многопользовательскую онлайн-игру, вам может потребоваться остановить игру, пока не произойдет повторное подключение.
- В одностраничном приложении вы можете начать сохранять изменения локально, а затем отправлять массовые обновления на сервер при повторном подключении.
- Если у вас есть традиционное приложение только с парой страниц «реального времени», вам может быть все равно, если соединение потеряно, поскольку в конечном итоге все будет согласовано.
Каркасы
Справедливо сказать, что эра WebSockets близится к нам. Независимо от того, какой язык программирования вы используете на сервере, будет существовать структура, включающая методы для обработки постоянных подключений и широковещательной передачи подключенным клиентам.
На стороне клиента эти структуры предоставляют вам методы решения проблем (повторного) управления соединениями и согласования состояний и дают вам простой способ подписки на различные «каналы». На стороне сервера они предлагают объединение открытых подключений и предоставляют механизмы широковещательной рассылки.
При внедрении в приложение функции реального времени не нужно отказываться от того, что вы знаете о HTTP, и начинать заново. Вы можете начать с добавления одного дополнительного маршрута (или канала), на который клиенты могут подписаться, что будет полезно, если будет обновляться в режиме реального времени.Рассматривайте это как улучшение производительности как для клиента, так и для сервера, клиент мгновенно обновляется, как только что-то происходит, и серверу не нужно отвечать на утомительный опрос:
Мы уже на месте? Мы уже на месте?
Теперь сервер может отвечать при запуске.
Я скажу вам, когда мы будем там
Ссылки
Используете ли вы WebSockets или отправляемые сервером события в производственной среде? Есть ли структура, которую я пропустил, заслуживает упоминания? Обязательно дайте мне знать в комментариях.
HTTP-маршрутизация | Центр разработки Heroku
Последнее обновление 19 октября 2020 г.
Платформа Heroku автоматически направляет HTTP-запросы, отправленные на имя (а) хоста вашего приложения, на ваши веб-серверы. Точкой входа для всех приложений в стеке Common Runtime является домен herokuapp.com
, который предлагает прямой путь маршрутизации к вашим веб-серверам.
В этой статье содержится подробная информация о том, как ведет себя маршрутизатор и как он соответствует спецификации HTTP.
Маршрут
Входящие запросы принимаются балансировщиком нагрузки, который предлагает завершение SSL. Отсюда они передаются прямо на набор маршрутизаторов.
Маршрутизаторы отвечают за определение местоположения веб-серверов вашего приложения и переадресацию HTTP-запроса одному из этих динамических устройств.
Необфусцированный путь запроса от конечного клиента через инфраструктуру Heroku к вашему приложению обеспечивает полную поддержку функций HTTP 1.1, таких как фрагментированные ответы, длительный опрос, веб-сокеты и использование асинхронного веб-сервера для обработки нескольких ответов от одного веб-процесса.Также поддерживается совместимость с HTTP 1.0.
Распределение запросов
Маршрутизаторы
используют алгоритм случайного выбора для балансировки HTTP-запросов через веб-серверы. В случаях, когда имеется большое количество дино, алгоритм может необязательно смещать свой выбор в сторону дино, находящихся в той же зоне доступности AWS, что и маршрутизатор, делающий выбор.
Запрос параллелизма
Каждый маршрутизатор поддерживает внутренний счетчик запросов для каждого приложения. В Common Runtime маршрутизаторы ограничивают количество одновременных запросов на одно приложение.Однако между маршрутизаторами отсутствует координация, поэтому этот предел запросов установлен для каждого маршрутизатора. Счетчик запросов на каждом маршрутизаторе имеет максимальный размер 50n (n = количество веб-серверов, работающих в вашем приложении). Если счетчик запросов на конкретном маршрутизаторе заполняется, последующие запросы к этому маршрутизатору немедленно вернут ответ h21 (слишком глубокий бэклог).
Поведение динамического подключения в Common Runtime
Когда Heroku получает HTTP-запрос, маршрутизатор устанавливает новое восходящее TCP-соединение со случайно выбранным веб-дино, работающим в Common Runtime.Если в соединении отказано или не было успешно установлено через 5 секунд, дино будет помещено в карантин, и никакие другие соединения не будут перенаправлены от этого маршрутизатора к дино в течение 5 секунд. Карантин применяется только к одному маршрутизатору. Поскольку каждый маршрутизатор хранит свой собственный список помещенных в карантин динамометрических станций, другие маршрутизаторы могут продолжать перенаправлять подключения к динамометрическим станциям.
Когда в соединении с динамометрическим дисплеем отказано или истекло время ожидания, маршрутизатор, обрабатывающий запрос, повторит запрос на другом диностенде.Будет сделано не более 10 попыток (или меньше, если у вас нет 10 работающих веб-динамометров), прежде чем будет возвращена ошибка h29 или h31.
Если все динамометрические станции помещены в карантин, маршрутизатор будет повторять попытку в течение 75 секунд (с постепенным откатом) перед обработкой ошибки H99.
Поведение при подключении Dyno в личных пространствах
Dynos в частном пространстве работают в собственной сети и на уровне маршрутизации и обмениваются данными друг с другом через частную сеть. Маршрутизатор в частных пространствах получает исходящие HTTP-запросы по набору разрешенных стабильных IP-адресов.
В отличие от поведения маршрутизатора в Common Runtime с веб-диностендами, маршрутизатор в Private Spaces не пересылает какие-либо соединения HTTP-запросов от одного веб-дино к другому, если в соединении отказано или истекло время ожидания. Вместо этого соединение прерывается через 30 секунд и возвращает ошибку h22. Дополнительные сведения о поведении маршрутизации в частных пространствах можно найти в статье «Маршрутизация в частных пространствах».
Таймауты
После того, как установлено динамическое соединение, HTTP-запросы имеют начальное 30-секундное окно, в котором веб-процесс должен вернуть данные ответа (либо завершенный ответ, либо некоторый объем данных ответа, чтобы указать, что процесс активен).Процессы, которые не отправляют ответные данные в течение начального 30-секундного окна, увидят в своих журналах ошибку h22.
После первоначального ответа каждый отправленный байт (либо от клиента, либо от процесса вашего приложения) сбрасывает скользящее 55-секундное окно. Если в течение этого 55-секундного окна данные не отправляются, соединение разрывается и регистрируется ошибка h25 или h38.
Дополнительную информацию можно найти в статье Тайм-аут запроса.
Одновременные подключения
Модель herokuapp.com
стек маршрутизации позволяет выполнять множество одновременных подключений к веб-серверам. Для производственных приложений вы всегда должны выбирать встроенный веб-сервер, который позволяет несколько одновременных подключений, чтобы максимизировать скорость отклика вашего приложения. Вы также можете воспользоваться преимуществами одновременных подключений для запросов с длительным опросом.
Практически все современные веб-фреймворки и встраиваемые веб-серверы поддерживают несколько одновременных подключений. Примеры веб-серверов, которые позволяют одновременную обработку запросов в динамометрическом стенде, включают Unicorn (Ruby), Goliath (Ruby), Puma (JRuby), Gunicorn (Python) и Jetty (Java).
Буферизация запросов
При обработке входящего запроса маршрутизатор устанавливает буфер для приема всей строки HTTP-запроса и заголовков запросов. Каждый из них имеет дополнительные ограничения, описанные в разделе «Проверка и ограничения HTTP». Тело запроса с четко определенной длиной содержимого передается с использованием буфера размером 1024 байта, непрерывно заполняется и сбрасывается. Это представляет собой размер, который охватывает подавляющее большинство запросов с точки зрения объема. Потоковые тела запросов (кодирование фрагментов) будут передаваться по мере поступления данных.Запрос начнет отправляться на динамометрический стенд только после того, как будет получен весь набор заголовков HTTP.
В результате каждый маршрутизатор буферизует раздел заголовка всех запросов и доставляет его на ваш дино так же быстро, как и наша внутренняя сеть. Динамометрический стенд защищен от медленных клиентов до тех пор, пока не потребуется прочитать тело запроса. Если вам нужна защита от клиентов, медленно передающих тело запроса, вам будут доступны заголовки запроса, чтобы вы могли принять решение о том, когда вы хотите отбросить запрос, закрыв соединение на динамометрическом стенде.
Буферизация ответа
Маршрутизатор поддерживает буфер размером 1 МБ для ответов от динамометрического стенда на каждое соединение. Это означает, что вы можете отправить ответ размером до 1 МБ до того, как скорость, с которой клиент получит ответ, повлияет на работу динамометрического стенда — даже если динамометрический стенд закроет соединение, маршрутизатор продолжит отправку буфера ответа клиенту. Скорость передачи ответов, размер которых превышает размер буфера 1 МБ, будет ограничиваться тем, насколько быстро клиент может получать данные.
Все заголовки считаются нечувствительными к регистру согласно спецификации HTTP.Заголовки X-Forwarded-For
, X-Forwarded-By
, X-Forwarded-Proto
и X-Forwarded-Host
не являются доверенными по соображениям безопасности, поскольку невозможно узнать порядок в котором были добавлены уже существующие поля (согласно перенаправленному расширению HTTP).
-
X-Forwarded-For
: исходный IP-адрес клиента, подключающегося к маршрутизатору Heroku -
X-Forwarded-Proto
: исходный протокол HTTP-запроса (пример: https) -
X-Forwarded-Port
: исходный порт HTTP-запроса (пример: 443) -
X-Request-Start
: временная метка unix (миллисекунды), когда запрос был получен маршрутизатором -
X-Request-Id
: идентификатор HTTP-запроса Heroku -
Via
: кодовое имя маршрутизатора Heroku
Формат журнала маршрутизатора Heroku
Информационные журналы
Это то, что отправляется в стоки журнала:
264 <158> 1 2012-10-11T03: 47: 20 + 00: 00 host heroku router - at = info method = GET path = / host = myapp.herokuapp.com request_id = 8601b555-6a83-4c12-8269-97c8e32cdb22 fwd = "204.204.204.204" dyno = web.1 connect = 1ms service = 18ms status = 200 байт = 13 tls_version = tls1.1 protocol = http
Это та же строка журнала при просмотре с журналами heroku
:
2012-10-11T03: 47: 20 + 00: 00 heroku [router]: at = info method = GET path = / host = myapp.herokuapp.com request_id = 8601b555-6a83-4c12-8269-97c8e32cdb22 fwd = " 204.204.204.204 "dyno = web.1 connect = 1ms service = 18ms status = 200 байт = 13 tls_version = tls1.1 протокол = http
-
метод
: метод HTTP-запроса -
путь
: путь HTTP-запроса и строка запроса -
хост
: HTTP-запросЗначение заголовка хоста
-
request_id
: идентификатор HTTP-запроса Heroku -
fwd
: HTTP-запросX-Forwarded-For
значение заголовка -
dyno
: имя dyno, обслуживающего запрос -
подключение
: время в миллисекундах, затраченное на установление соединения с внутренним веб-процессом -
служба
: количество времени в миллисекундах, затраченное на проксирование данных между внутренним веб-процессом и клиентом -
статус
: код ответа HTTP -
байт
: количество байтов, переданных из внутреннего веб-процесса клиенту -
протокол
: указывает протокол запроса -
tls_version
: версия TLS, используемая для подключения.Возможные значения: ssl3.0, tls1.0, tls1.1, tls1.2, tls1.3 или unknown. Примечание: это только для частных пространств.
Журналы ошибок
Это то, что отправляется в стоки журнала:
277 <158> 1 2012-10-11T03: 47: 20 + 00: 00 host heroku router - at = error code = h22 desc = "Request timeout" method = GET path = / host = myapp.herokuapp.com request_id = 8601b555-6a83-4c12-8269-97c8e32cdb22 fwd = "204.204.204.204" dyno = web.1 connect = service = 30000ms status = 503 байта = 0 протокол = http
Это та же строка журнала при просмотре с журналами heroku
:
2012-10-11T03: 47: 20 + 00: 00 heroku [router]: at = код ошибки = h22 desc = "Тайм-аут запроса" метод = GET path = / host = myapp.herokuapp.com request_id = 8601b555-6a83-4c12-8269-97c8e32cdb22 fwd = "204.204.204.204" dyno = web.1 connect = service = 30000ms status = 503 bytes = 0 protocol = http
Кэширование
Приложения, обслуживающие большие объемы статических ресурсов, могут использовать кеширование HTTP для повышения производительности и снижения нагрузки.
Веб-сокеты
Функциональность
WebSocket поддерживается для всех приложений.
Ответы в формате Gzip
Поскольку запросы к приложениям Common Runtime выполняются непосредственно на сервер приложений, а не через прокси-сервер HTTP, например nginx, любое сжатие ответов должно выполняться в вашем приложении.
Поддерживаемые методы HTTP
HTTP-стек Heroku поддерживает любой HTTP-метод (иногда называемый «глаголом»), даже те, которые не определены в RFC, за исключением следующего: CONNECT.
Обычно используемые методы включают GET, POST, PUT, DELETE, HEAD, OPTIONS и PATCH. Имена методов ограничены длиной 127 символов.
Ожидать: 100-продолжить
Протокол HTTP имеет несколько встроенных механизмов, помогающих клиентам взаимодействовать с
серверов, чтобы улучшить обслуживание в целом.Одним из таких механизмов является
Expect: 100-continue Заголовок
, который можно отправить вместе с
запросы [1].
Этот заголовок и значение должны использоваться дружественными клиентами при отправке
большие HTTP-запросы и хотите знать, может ли сервер их безопасно принять раньше
отправляя его, чтобы предотвратить проблемы с отказом в обслуживании и разрешить некоторые
оптимизации. HTTP-клиент cURL является наиболее известным
библиотека, использующая этот механизм, делая это для любого тела содержимого размером более 1 КБ
(недокументированное поведение).
Всякий раз, когда запрашивается разрешение, серверу разрешается ответить
100 Продолжить
HTTP-статус,
что позволяет клиенту знать, что он готов к
принять запрос и позволить клиенту продолжить. Если сервер не может работать
с его помощью он может возвращать любой другой ответ HTTP, который имеет смысл для него, например
413 Запрос слишком большой объект
если он не хочет справляться с нагрузкой, и может
при желании закрыть соединение сразу после факта.
Таким образом, между любыми двумя клиентами и сервером механизм, который имеет место, может
выглядят примерно так для обычного звонка:
[Клиент] [Сервер]
| -------- Частичный запрос --------> |
| <--------- 100 Продолжить ---------- |
| --------- Тело запроса ----------> |
| <----------- Ответ ------------ |
Или, если запрос отклонен:
[Клиент] [Сервер]
| -------- Частичный запрос --------> |
| <- 413 Слишком большой объект запроса - |
Однако механизм должен быть более устойчивым, потому что не все серверы и
клиенты могут понять этот механизм.Таким образом, если клиент не знает
может ли сервер принимать и соблюдать заголовки Expect: 100-Continue
,
он должен отправлять фактическое тело после определенного периода времени:
[Клиент] [Сервер]
| -------- Частичный запрос --------> |
| |
| |
| |
| --------- Тело запроса ----------> |
| <----------- Ответ ------------ |
По умолчанию многие веб-серверы не обрабатывают Expect: 100-continue
как механизм.Следовательно, HTTP-маршрутизаторы Heroku автоматически вставят ответ 100 Continue
от имени приложения, к которому он направляется, и позже пересылают данные.
Это более или менее полностью отключает механизм в том, что касается веб-сервера дино.
Включение поддержки 100-Continue
Непрерывная поддержка теперь доступна (для участников бета-программы Heroku) через функцию лабораторий Heroku:
$ heroku labs: включить http-end-to-end-continue
Если расширение включено, общий поток функции 100-Continue восстанавливается, и маршрутизатор прозрачно передает заголовки expect: 100-continue
и связанные с ними 100 continue
ответов.
Эта функция имеет свой собственный набор угловых вариантов и поведения, которые, однако, необходимо указать.
Угловые шкафы
Есть набор специальных угловых корпусов, которые могут поставляться с этим типом
запрос.
Исходный HTTP 1.1 RFC (RFC 2068)
разрешено использование частичного ответа 100 Continue
, чтобы сервер мог сказать «
весь запрос не был проанализирован, но продолжайте, я не отрицаю
прочь". Более поздние RFC (RFC
2616 например)
содержать механизм Expect: 100-continue
и повторно использовать 100
как часть механизма, определенного в предыдущем
Продолжить частичный ответ
раздел текста.
По причинам обратной совместимости сервер может отправить 100
, не получив соответствующий заголовок
Продолжить Expect
, но сильно
посоветовал не делать этого.
Второй угловой случай заключается в том, что сервер может решить не отправлять обратно 100
, если он сначала начал получать и обрабатывать данные тела
Продолжить ответ
рука, о которой клиент должен знать.
Серверы
также должны быть осторожны при разборе заголовков Expect
, учитывая, что они
может содержать более одного значения .Например, Expect: 100-continue, auth
.
может быть отправлен, когда ожидается, что сервер обработает большое тело, при запросе
пройти аутентификацию перед тем, как сделать это. Технически может быть столько значений, сколько
желательно в заголовке Expect
с поведением, определенным исключительно для
ради клиента и сервера.
Другие особые случаи возникают из-за неожиданных взаимодействий, возникающих в результате
несколько заголовков, управляющих потоком подключения. Например:
Это поведение не определено исходными спецификациями, и Heroku
маршрутизатор должен принять решение относительно них, чтобы обеспечить согласованный
поведение.
Требования к прокси
Несмотря на то, что заголовок Expect
определен как сквозной заголовок (только
клиент и сервер должны заботиться о них, объясняя, почему любой термин
может быть использован в нем), сам механизм 100 Continue
(и общий
Expect
поддержки поведения) требует координации с прокси-серверами и выполняется поэтапно.
В RFC для них добавлены особые условия:
- Прокси-сервер должен передавать заголовок как есть, знает ли он, может ли сервер
справиться или нет - Если прокси-сервер знает, что сервер, к которому он направляется, имеет версию HTTP 1.0
или ниже, он должен отклонить запрос со статусом417 Expectation Failed
,
но возможно, он об этом не знает. - Клиент HTTP 1.0 (или более ранней версии) мог отправить запрос без
Expect: 100-Continue заголовок
, и сервер все еще может ответить на него, используя
HTTP-код100 Continue
(как часть RFC 2068),
в этом случае прокси должен полностью удалить ответ и дождаться ретрансляции
окончательный статус.
Маршрутизатор Heroku 100-продолжить поддержку
Маршрутизатор допускает некоторые вольности в отношении неопределенного поведения и углов
случаев, упомянутых ранее:
-
100 Продолжить
будет удален как ответ, если клиент является HTTP 1.0 (или
ранее) и заголовокExpect: 100-continue
не является частью
запрос, и будет перенаправлен в противном случае, несмотря ни на что. - Маршрутизатор будет , а не , для запуска потребуется ответ
100 Continue
отправка тела запроса, но оставит время ожидания на усмотрение клиента (без
нарушение обычных правил бездействия
для подключений на Heroku) - Маршрутизатор автоматически ответит сообщением
417 Expectation Failed
ответ и закройте соединение с динамометрическим станком, если заголовокExpect
содержит любое значение, кроме100 Продолжить
(без учета регистра) - Если запрошено обновление WebSocket, оно будет отправлено на динамометрический стенд как есть, а
маршрутизатор выполнит любой ответ:100 Продолжить
статус может игнорировать
обновление WebSocket и возврат любого кода (как обычно) и переключение101
Протокол
игнорирует поведение заголовковExpect
.Обратите внимание, что в целях соблюдения
HTTPbis Draft,
Маршрутизатор по-прежнему будет искать протокол коммутации101
после
100 Продолжить
получено от сервера. - Маршрутизатор будет игнорировать
Соединение: закрыть
на100 Продолжить
и только
соблюдайте его после получения окончательного ответа. Учитывая, что RFC указывает, что
соединение должно быть закрыто «после завершения текущего запроса / ответа»,
и что100
не является статусом терминала, соединение будет закрыто только после
получив терминальный статус.Однако обратите внимание, что, поскольку соединение: закрыть
является поэтапным механизмом, маршрутизатор не обязательно закроет
соединение с клиентом, и может не пересылать его. - Маршрутизатор удаляет все заголовки из ответа
100 Continue
, если нет
заголовок предписан RFC, что значительно упрощает реализацию. - Маршрутизатор вернет код ошибки 5xx, если сервер вернет
100 Продолжить
после первоначального ответа100 Продолжить
.Роутер
еще не поддерживает бесконечные потоки 1xx. - Маршрутизатор закроет соединение с сервером после
код состояния терминала, независимо от того, предшествовал ли ему код100 Продолжить
или нет
заранее - подключения к динамометрическим станциям не поддерживаются. - Маршрутизатор закроет соединение с клиентом после
код состояния терминала, который был , а не , которому предшествовал ответ100 Продолжить
.
Это избавит клиента от необходимости отправлять тело запроса до того, как
наличие возможности сервера обработать следующий запрос.
Другие механизмы должны соблюдаться как есть протоколом и маршрутизатором.
должен пересылать запросы, как указано в RFC.
Поддерживаемые версии HTTP
В мире используются четыре основных версии HTTP: HTTP / 0.9, HTTP / 1.0, HTTP / 1.1 и HTTP / 2.
Маршрутизатор Heroku поддерживает только клиентов HTTP / 1.0 и HTTP / 1.1. HTTP / 0.9 и
ранее больше не поддерживаются. SPDY и HTTP / 2 здесь не поддерживаются.
время.
Поведение маршрутизатора должно максимально соответствовать HTTP / 1.1
технические характеристики. Однако для HTTP / 1.0 должны быть сделаны особые исключения:
- Маршрутизатор будет рекламировать себя как использующий HTTP / 1.1 независимо от того,
клиент использует HTTP / 1.0 или нет. - Маршрутизатор возьмет на себя необходимые преобразования из
фрагментированный ответ на обычный HTTP-ответ. Чтобы обойтись без
накопив потенциально гигабайты данных, ответ клиенту будет
ограничены прекращением соединения (см. пункт
4.4.5) - Маршрутизатор предполагает, что клиент хочет закрыть соединение на каждом
запрос (без сохранения активности). - Клиент HTTP / 1.0 может отправить запрос с явным соединением
: keep-alive
заголовок. Несмотря на то, что механизм поддержания активности не был определен еще в 1.0 (он был
ad-hoc), маршрутизатор предполагает, что запрошенное поведение
аналогично поведению HTTP / 1.1 на этом этапе.
HTTP-проверка и ограничения
Запрос на подтверждение:
- В случае фрагментированного кодирования и длины содержимого оба присутствуют в
запрос, маршрутизатор будет отдавать предпочтение фрагментированным
кодирование. - Если присутствует несколько полей длины содержимого, и что они имеют одинаковые
length, они будут объединены в один заголовок длиной - Если заголовок длины содержимого содержит несколько значений (
длина содержимого: 15,24
)
или запрос содержит несколько заголовков длины содержимого с несколькими значениями,
запрос будет отклонен кодом 400. - Заголовки ограничены 8192 байтами на строку (и 1000 байтов для заголовка
имя) - Поэтапные заголовки будут удалены во избежание путаницы
- Максимум 1000 заголовков в запросе
- Строка запроса HTTP ограничена 8192 байтами
- Строка запроса предполагает разделение отдельных пробелов между командой, путем и версией HTTP.
Подтверждение ответа:
- Поэтапные заголовки будут удалены, чтобы избежать путаницы
- Заголовки ограничены 512 КБ на строку
- Файлы cookie явно ограничены 8192 байтами. Это для защиты от
общие ограничения (например, налагаемые CDN), которые редко принимают большие
значения cookie. В таких случаях разработчик мог случайно установить большой
файлы cookie, которые будут отправлены обратно пользователю, который затем увидит все
его или ее запросы отклонены. - Строка состояния (
HTTP / 1.1 200 OK
) ограничена 8192 байтами длиной
Приложения, которые нарушают эти ограничения в ответах, увидят, что их запросы завершаются ошибкой с ответом 502 Bad Gateway, и в поток журнала приложения будет вставлена ошибка h35. Клиенты, которые нарушают эти ограничения в запросах, увидят, что их запрос завершился ошибкой с ответом 400 Bad Request.
Кроме того, ожидается, что запросы и ответы HTTP / 1.1 будут
keep-alive
по умолчанию, если исходный запрос имел явное соединение :
от маршрутизатора к динамометрическому станку, дино может отправить ответ
закройте заголовок
ограничены завершением соединения, без конкретной кодировки содержимого или
явная длина содержимого.
Обновления протокола
В то время как предыдущий маршрутизатор Heroku ограничивал обновления протокола HTTP до WebSockets.
только новый роутер вообще допускает любое обновление.
Конкретные моменты, связанные с внедрением:
- Любая HTTP-команда может использоваться с обновляемым соединением
- Хотя
HEAD
HTTP-глаголы обычно не требуют правильного ответа
отправлено по линии (например, относительно длины содержимого),HEAD
запросов
явно предназначены для работы с ответами101 Switching Protocols
.Динозавр
который не хочет обновляться, должен отправить другой код статуса, а
соединение не будет модернизировано
Не поддерживается
- SPDY
- HTTP / 2
- IPv6
-
Ожидайте заголовков
с любым содержимым, кроме100-continue
(дает 417) - Расширения HTTP, такие как WEBDAV
- Ответ HEAD, 1xx, 204 или 304 с кодировкой длины содержимого или фрагментированной кодировкой
прокси не пытается передать тело, которое никогда не придет - Окончания строки заголовка, отличные от CRLF (
\ r \ n
) - Кэширование содержимого HTTP
- Кэширование HTTP-версий серверов, работающих на dynos
- Давно назначенные неработающие соединения.Лимит установлен на 1 минуту.
перед закрытием неактивного соединения. - запросов HTTP / 1.0 без заголовка
Host
, даже если полный URL
отправлено в строке запроса. - Маршрутизация TCP
Что это такое и как это исправить
Тайм-аут запроса 408 - это код статуса HTTP-ответа
, указывающий, что сервер не получил полный запрос от клиента в течение установленного сервером периода тайм-аута. 408 Request Timeout
Код ошибки выглядит как аналогично ошибке 504 Gateway Timeout
, которую мы исследовали в предыдущей статье, что указывает на то, что сервер, действующий как шлюз или прокси, истек.Однако ошибка 408 Request Timeout
не является сообщением от шлюза или прокси-сервера где-то в цепочке узлов, а является прямым сообщением от активного сервера, к которому клиент подключился (например, веб-сервера)
Может быть трудно найти причину неожиданных кодов ответа HTTP, и код ошибки 408 Request Timeout
не является исключением. С потенциальным пулом из более 50 кодов состояния , используемых для представления сложных отношений между клиентом, веб-приложением, веб-сервером и (возможно) несколькими сторонними веб-службами, определение причины конкретного кода состояния может быть сложно, даже в самых лучших обстоятельствах.
В этой статье мы более подробно рассмотрим 408 Request Timeout
, посмотрев, что может вызвать появление этого сообщения, включая несколько советов, которые вы можете использовать для диагностики и отладки появления этой ошибки в вашем собственном приложении. Мы даже рассмотрим ряд самых популярных систем управления контентом ( CMS,
) на предмет потенциальных проблемных областей, которые могут привести к тому, что ваш собственный веб-сайт может неожиданно генерировать ошибки 408 Request Timeout
. Давайте нырнем!
На стороне сервера или на стороне клиента?
Все коды состояния ответа HTTP в категории 4xx
считаются ответами клиента об ошибке
.Ошибки в категории 4xx
контрастируют с ошибками из категории 5xx
, такими как вышеупомянутый 504 Gateway Timeout
, который мы исследовали ранее, которые считаются ответами сервера на ошибку
. Тем не менее, появление ошибки 4xx
не обязательно означает, что проблема связана с клиентской стороной («клиентом» в данном случае обычно является веб-браузер или устройство, используемое для доступа к приложению). Часто, если вы пытаетесь диагностировать проблему в собственном приложении, вы можете сразу же игнорировать большую часть клиентского кода и компонентов, таких как HTML, каскадные таблицы стилей (CSS), клиентский JavaScript и т. Д.Это также не относится к только к веб-сайтам. В приложениях для смартфонов часто реализуются современные пользовательские интерфейсы, которые фактически негласно работают на обычных веб-приложениях.
С другой стороны, сервер может быть основной причиной ошибки 408 Request Timeout
. В некоторых случаях сервер может быть неправильно настроен и может неправильно обрабатывать запросы, что может привести к ответам кода 408
и другим неприятным проблемам с маршрутизацией трафика.Мы рассмотрим некоторые из этих сценариев (и потенциальных решений) ниже, но имейте в виду, что, хотя время ожидания запроса 408
считается ответом об ошибке клиента
, это не обязательно означает, что мы можем исключить либо клиент или сервер как виновник в этом сценарии. В этих ситуациях сервер
по-прежнему является сетевым объектом, который производит 408 Request Timeout
и возвращает его в качестве кода ответа HTTP клиенту
, но может быть, что клиент каким-то образом вызывает проблему. .
Начните с тщательного резервного копирования приложений
Как обычно, лучше сначала перестраховаться, чем что-то напортачить и потом пожалеть об этом. Таким образом, критически важно, , чтобы вы выполнили полное резервное копирование вашего приложения, базы данных и всех других компонентов вашего веб-сайта или приложения , прежде чем попытается исправить какие-либо исправления или изменения в системе. Еще лучше, если у вас есть возможность, создайте полную копию приложения и прикрепите копию на вторичном промежуточном сервере , который либо неактивен, либо общедоступен.Это даст вам чистую площадку для тестирования, на которой можно протестировать все возможные исправления, необходимые для решения проблемы, без угрозы безопасности или неприкосновенности вашего действующего приложения.
Диагностика тайм-аута запроса 408
A 408 Request Timeout Код ответа
указывает, что сервер не получил полный запрос от клиента в течение определенного периода времени, отслеживаемого сервером (то есть периода тайм-аута ). Как указано в стандарте RFC7235 HTTP / 1.1 Semantics and Content, сервер документов должен включать специальный заголовок
Connection
с директивой close
как часть своего ответа (e.грамм. Соединение: закрыть
), который информирует клиента о том, что соединение должно быть закрыто. Проще говоря, код 408
информирует клиента о том, что сервер решил закрыть соединение, а не продолжать ждать завершения транзакции. После получения заголовка Connection: close
клиент может выбрать повторение исходного запроса, используя новое соединение.
Большинство современных браузеров реализуют механизмы предварительного подключения HTTP, которые предоставляют агенту пользователя (т.е.е. браузер), чтобы ускорить общий просмотр веб-страниц, по существу предсказывая , какие ресурсы - и, следовательно, соединения - клиент может использовать в ближайшем будущем. Полный объем того, как браузеры используют эти механизмы, выходит далеко за рамки этой статьи, но вы можете проверить документацию W3C Resource Hints для получения дополнительных сведений.
Устранение неполадок на стороне клиента
Поскольку 408 Request Timeout
является кодом ответа об ошибке клиента
, лучше всего начать с устранения любых потенциальных проблем на стороне клиента, которые могут вызывать эту ошибку.Вот несколько советов, которые можно попробовать в браузере или устройстве, на котором возникают проблемы.
Проверить запрошенный URL
Самая распространенная причина тайм-аута запроса 408
- это просто ввод неверного URL-адреса. Многие серверы надежно защищены, чтобы предотвратить неожиданные запросы к ресурсам, к которым клиент / пользовательский агент не должен иметь доступа. Возможно, запрошенный URL-адрес немного неверен, что заставляет пользовательский агент запрашивать непредусмотренный ресурс, который может быть перенаправлен через прокси-сервер, требующий аутентификации.Например, запрос к URI https://airbrake.io/login
может направлять запросы через отдельный прокси-сервер, используемый для обработки аутентификации пользователя. Если исходный запрос не содержал соответствующих учетных данных, результатом может быть ответ с ошибкой 408 Request Timeout
. Всегда рекомендуется дважды проверять точный URL, который возвращает ошибку 408 Request Timeout
, чтобы убедиться, что это целевой ресурс.
Отладка общих платформ
Если вы запускаете стандартные пакеты программного обеспечения на сервере, который отвечает 408 Request Timeout
, вы можете сначала изучить стабильность и функциональность этих платформ.Наиболее распространенные системы управления контентом, такие как WordPress, Joomla !, и Drupal, как правило, хорошо протестированы из коробки, но как только вы начнете вносить изменения в базовые расширения или код PHP
(язык, на котором почти все современные системы управления контентом написаны на), слишком легко вызвать непредвиденную проблему, которая приводит к 408 Request Timeout
.
Ниже приведены несколько советов, которые помогут вам устранить неполадки на некоторых из этих популярных программных платформ.
Откат последних обновлений
Если вы недавно обновили саму систему управления контентом незадолго до появления 408 Request Timeout
, возможно, вы захотите вернуться к предыдущей версии, которую вы установили, когда все работало нормально. Точно так же любые расширения или модули, которые вы, возможно, недавно обновили, также могут вызвать проблемы на стороне сервера, поэтому возврат к предыдущим версиям также может помочь. Чтобы получить помощь с этой задачей, просто выполните Google «понизьте версию [PLATFORM_NAME]» и следуйте инструкциям.Однако в некоторых случаях некоторые CMS на самом деле не предоставляют возможности понижения версии, что указывает на то, что они считают базовое приложение вместе с каждой новой выпущенной версией чрезвычайно стабильным и свободным от ошибок. Обычно это происходит с более популярными платформами, поэтому не бойтесь, если вам не удастся найти простой способ вернуть платформу к более старой версии.
Удаление новых расширений, модулей или подключаемых модулей
В зависимости от конкретной системы управления контентом, которую использует ваше приложение, точное имя этих компонентов будет отличаться, но они служат одной и той же цели для каждой системы: улучшение возможностей и функций платформы сверх того, на что она обычно способна вне коробка.Но будьте осторожны: такие расширения могут более или менее полностью контролировать систему и вносить практически любые изменения, будь то код PHP
, HTML, CSS, JavaScript или база данных. Таким образом, может быть целесообразно удалить все новые расширения, которые могли быть недавно добавлены. Опять же, Google - это расширение для официальной документации и помощи в этом процессе.
Проверить наличие непредвиденных изменений в базе данных
Стоит отметить, что даже , если вы удаляете расширение через панель управления CMS, не гарантирует , что изменения, внесенные расширением, были полностью отменены.Это особенно верно для многих расширений WordPress, которым в приложении предоставляется карт-бланш, включая полные права доступа к базе данных. Если автор расширения явно не закодирует такие вещи, существуют сценарии, в которых расширение может изменять записи базы данных, которые не «принадлежат» самому расширению, а вместо этого создаются и управляются другими расширениями (или даже самой базовой CMS). В этих сценариях расширение может не знать, как отменить изменения в записях базы данных, поэтому оно будет игнорировать такие вещи во время удаления.Диагностика таких проблем может быть сложной задачей, но я лично сталкивался с такими сценариями несколько раз, поэтому ваш лучший курс действий, если вы достаточно уверены, что расширение является вероятной причиной 408 Request Timeout
, - это открыть базу данных. и вручную просматривать таблицы и записи, которые, вероятно, были изменены расширением.
Прежде всего, не бойтесь сообщать о своей проблеме в Google. Попробуйте выполнить поиск по конкретным терминам, имеющим отношение к вашей проблеме, например по названию CMS вашего приложения, вместе с 408 Request Timeout
.Скорее всего, вы найдете кого-то, кто столкнулся с той же проблемой.
Устранение неполадок на стороне сервера
Если вы не запускаете приложение CMS - или даже если оно есть, но вы уверены, что время ожидания запроса 408
не связано с этим - вот несколько дополнительных советов, которые помогут вам устранить причину проблемы. на стороне сервера.
Подтвердите конфигурацию вашего сервера
Ваше приложение, вероятно, работает на сервере, который использует одно из двух самых популярных программных веб-серверов, Apache
или nginx
.На момент публикации оба этих веб-сервера составляют 84% программного обеспечения веб-серверов в мире! Таким образом, одним из первых шагов, которые вы можете предпринять, чтобы определить, что может быть причиной этих кодов ответа 408 Request Timeout
, является проверка файлов конфигурации программного обеспечения вашего веб-сервера на предмет непреднамеренного перенаправления или инструкций по обработке запросов.
Чтобы определить, какой веб-сервер использует ваше приложение, вам нужно найти ключевой файл. Если ваш веб-сервер - Apache, поищите .htaccess
в корневом каталоге файловой системы вашего веб-сайта. Например, если ваше приложение размещено на общем хосте, у вас, скорее всего, будет имя пользователя, связанное с учетной записью хостинга. В таком случае корневой каталог приложения обычно находится по пути / home /
, поэтому файл .htaccess
будет по адресу /home/
.
Если вы нашли файл .htaccess
, откройте его в текстовом редакторе и найдите строки, в которых используются директивы KeepAliveTimeout
или RequestReadTimeout
. KeepAliveTimeout
является частью модуля core
, а RequestReadTimeout
- из модуля reqtimeout
в Apache. Подробное описание того, как работают эти директивы, выходит далеко за рамки данной статьи, однако основная концепция заключается в том, что эти директивы тайм-аута информируют сервер о том, что входящим клиентским запросам требуется только определенное время, прежде чем они будут считаться неудачными и закрытыми через ответ 408
.
Например, здесь мы используем директиву RequestReadTimeout
для установки тайм-аутов заголовка и тела 15
и 30
секунд:
Заголовок RequestReadTimeout = 15, тело = 30
Найдите какие-либо странные директивы тайм-аута в .htaccess
, которые, похоже, не принадлежат, затем попробуйте временно закомментировать их (используя префикс символов #
) и перезапустите веб-сервер, чтобы увидеть, решит ли это проблему.
С другой стороны, если ваш сервер работает на nginx
, вам нужно будет искать совершенно другой файл конфигурации. По умолчанию этот файл называется nginx.conf
и находится в одном из нескольких общих каталогов: / usr / local / nginx / conf
, / etc / nginx
или / usr / local / etc / nginx.
.После обнаружения откройте nginx.conf
в текстовом редакторе и найдите директивы client_body_timeout
, client_header_timeout
или keepalive_timeout
, которые являются частью модуля http_core
Nginx. Например, вот простая директива блока
(то есть именованный набор директив), которая настраивает виртуальный сервер для airbrake.io
и устанавливает таймауты заголовка и тела клиента на 15
и 30
секунд соответственно:
сервер {
слушать 80;
слушайте 443 ssl;
имя_сервера airbrake.io;
client_header_timeout 15 с;
client_body_timeout 30 с;
keepalive_timeout 60 с;
}
Просмотрите файл nginx.conf
на предмет аномальных директив _timeout
и закомментируйте любые отклонения перед перезапуском сервера, чтобы увидеть, была ли решена проблема.
Параметры конфигурации для каждого типа веб-сервера могут сильно различаться, поэтому мы просто перечислим несколько популярных, чтобы дать вам некоторые ресурсы для просмотра, в зависимости от того, на каком типе сервера работает ваше приложение:
Просмотрите журналы
Почти каждое веб-приложение будет вести журналы на стороне сервера в той или иной форме. Журналы приложений
обычно представляют собой историю того, что приложение делало, например, какие страницы были запрошены, к каким серверам оно подключалось, какие результаты из базы данных оно предоставляет и так далее. Журналы сервера
связаны с фактическим оборудованием, на котором запущено приложение, и часто предоставляют подробные сведения о работоспособности и состоянии всех подключенных служб или даже самого сервера. Google «ведет журнал [PLATFORM_NAME]», если вы используете CMS, или «журналы [PROGRAMMING_LANGUAGE]» и «журналы [OPERATING_SYSTEM]», если вы запускаете собственное приложение, чтобы получить дополнительную информацию о поиске соответствующих журналов.
Отладка кода или сценариев приложения
Если все остальное не помогает, возможно, проблема в каком-то настраиваемом коде в вашем приложении. Попробуйте определить причину возникновения проблемы, отладив приложение вручную и проанализировав журналы приложений и серверов. В идеале, сделайте копию всего приложения на локальном компьютере разработки и выполните пошаговый процесс отладки, который позволит вам воссоздать точный сценарий, в котором произошел 408 Request Timeout
, и просмотреть код приложения на момент что-то пойдет не так.
Независимо от причины - и даже если вам удалось исправить эту конкретную ошибку на этот раз - появление проблемы, такой как 408 Request Timeout
в вашем собственном приложении, является хорошим признаком того, что вы можете захотеть реализовать инструмент управления ошибками, который поможет вам автоматически обнаруживать ошибки и предупредит вас, как только они возникнут. Программное обеспечение Airbrake для мониторинга ошибок обеспечивает мониторинг ошибок в реальном времени и автоматическую отчетность об исключениях для всех ваших проектов разработки.Современная веб-панель управления Airbrake гарантирует, что вы будете получать круглосуточную информацию о состоянии вашего приложения и количестве ошибок. Независимо от того, над чем вы работаете, Airbrake легко интегрируется со всеми наиболее популярными языками и фреймворками. Кроме того, Airbrake упрощает настройку параметров исключений, предоставляя вам полный контроль над активной системой фильтрации ошибок, так что вы собираете только самые важные ошибки.
Ознакомьтесь с программным обеспечением Airbrake для мониторинга ошибок сегодня и убедитесь сами, почему так много лучших инженерных команд мира используют Airbrake, чтобы революционизировать свои методы обработки исключений!
Как подключить NGINX к PHP-FPM с помощью UNIX или TCP / IP Socket
Веб-сервер NGINX (как обратный прокси) обслуживает приложения PHP через протокол FastCGI (как сервер внутренних приложений). NGINX использует PHP-FPM (FastCGI Process Manager), альтернативную реализацию PHP FastCGI , которая работает в фоновом режиме как демон, прослушивая запросы CGI . Он поставляется с дополнительными функциями, предназначенными для работы с сильно загруженными веб-сайтами или веб-приложениями, но его можно использовать для сайтов любого размера.
Не только PHP-FPM поддерживает конфигурацию пулов ресурсов FastCGI , но также улучшает многие внутренние компоненты FastCGI и увеличивает отчеты об ошибках, завершение скриптов и многое другое.Он включает демонизацию PHP, управление процессами, динамическое количество процессов, из которых могут поступать запросы, заголовок ошибки, поддержку ускоренной загрузки и многое другое.
Для приема запросов FastCGI от NGINX , PHP-FPM может либо прослушивать сокет TCP / IP , либо сокет домена UNIX. Какой бы адрес вы ни выбрали, это то, что NGINX использует для подключения (запросы прокси) к PHP-FPM с использованием директивы fastcgi_pass
.
В этом руководстве объясняется, как настроить NGINX для серверных приложений PHP с использованием PHP-FPM . В нем описывается, когда использовать сокет TCP / IP или сокет домена UNIX для подключения NGINX к PHP-FPM и почему.
В этом руководстве предполагается, что в вашей системе Linux установлены NGINX и PHP-FPM , в противном случае см .:
Что мне использовать: сокет домена UNIX или сокет TCP / IP?
Доменные сокеты UNIX (или IPC ) - это средства межпроцессного взаимодействия (IPC), которые обеспечивают эффективный обмен данными между процессами, работающими в одной операционной системе, в то время как сокеты TCP / IP (или Internet Domain ) разрешить процессам обмениваться данными по сети.
В отличие от сокета TCP / IP , который идентифицирует сервер по IP-адресу и порту (например, 127.0.0.1:9000 ), вы можете привязать сервер к сокету домена UNIX, используя путь к файлу (например, / run / php-fpm / www.sock ), который виден в файловой системе.
Доменный сокет UNIX - это особый тип файла - к нему применяются разрешения для файлов и каталогов (как и в случае с любым другим типом файлов UNIX), и его можно использовать для ограничения того, какие процессы на хосте могут читать и записывать в файл. , (и, таким образом, общаться с внутренним сервером).
Таким образом, сокет домена UNIX является безопасным, поскольку его могут использовать только процессы на локальном хосте. Сокет TCP / IP может быть открыт для доступа в Интернет, создавая угрозу безопасности, если не будут реализованы дополнительные меры безопасности, такие как брандмауэр.
Важно отметить, что использование сокета домена UNIX - это не то же самое, что использование сокета TCP / IP с точки зрения производительности, несколько тестов и тестов показали, что сокеты домена UNIX работают быстрее. Главный недостаток сокетов домена UNIX заключается в том, что они менее масштабируемы, они поддерживают только межпроцессное взаимодействие в рамках одной и той же операционной системы (ОС).
Где я могу настроить адрес прослушивания PHP-FPM?
Вы можете настроить адрес , который прослушивает PHP-FPM , в файле конфигурации пула ресурсов. Обратите внимание, что с PHP-FPM вы можете запускать несколько пулов процессов с разными настройками. Пул по умолчанию называется www
.
Расположение файла конфигурации пула ресурсов зависит от способа установки PHP и PHP-FPM в системе Linux (будь то версия по умолчанию / одна версия или несколько версий одновременно).
Например, в CentOS 8 с единственной версией все файлы конфигурации PHP расположены в каталоге / etc
, а файл конфигурации по умолчанию PHP-FPM pool (www)
- / etc / php -fpm.d / www.conf :
Чтобы вывести список всех файлов конфигурации PHP, используйте следующую команду ls.
# ls / etc / php *
Список всех файлов конфигурации PHP
В Ubuntu 20.04 файлы конфигурации PHP расположены в каталоге / etc / php /
и в файле конфигурации пула PHP-FPM по умолчанию
(www)
это / etc / php /
:
$ ls /etc/php/7.4/
Список всех файлов конфигурации PHP в Ubuntu
Настройка PHP-FPM для прослушивания в доменном сокете UNIX
Чтобы настроить PHP-FPM на прослушивание сокета домена UNIX, откройте файл конфигурации пула PHP-FPM по умолчанию, используя свой любимый текстовый редактор.
# vim /etc/php-fpm.d/www.conf # Ubuntu / Debian ИЛИ ЖЕ $ sudo vim /etc/php/7.4/fpm/pool.d/www.conf # CentOS / RHEL / Fedora
Затем найдите директиву listen и задайте ей путь к файлу сокета домена UNIX следующим образом.Обратите внимание, что в большинстве установок по умолчанию используется доменный сокет UNIX.
слушайте = /run/php/php7.4-fpm.sock # Ubuntu / Debian ИЛИ ЖЕ слушайте = /run/php-fpm/www.sock # CentOS / RHEL / Fedora
Если вы используете сокет домена UNIX, вам также необходимо установить соответствующие разрешения на чтение / запись для файла, чтобы разрешить соединения с веб-сервером NGINX. По умолчанию NGINX запускается как пользователь и группа nginx на CentOS / RHEL / Fedora и www-data на Ubuntu и Debian .
Итак, найдите параметры listen.owner
и listen.group
и установите их соответственно. Также установите режим 0660 с помощью параметра listen.mode
.
------------- В Debian и Ubuntu ------------- listen.owner = www-data listen.group = www-data listen.mode = 0660 ------------- В CentOS / RHEL и Fedora ------------- listen.owner = nginx listen.group = nginx Слушать.mode = 0660
Обратите внимание, что если разрешения для файла сокета домена UNIX установлены неправильно, NGINX может вернуть ошибку неверного шлюза.
Конфигурация PHP-FPM
Настройка PHP-FPM для прослушивания сокета TCP / IP
Хотя сокет домена UNIX быстрее, чем сокет TCP / IP, первый менее масштабируемый, поскольку он может поддерживать межпроцессное взаимодействие только в одной и той же ОС. Если NGINX и сервер внутренних приложений ( PHP-FPM ) работают в разных системах, вам необходимо настроить PHP-FPM для прослушивания сокета TCP / IP для соединений.
В файле конфигурации пула PHP-FPM установите адрес прослушивания
следующим образом. Убедитесь, что выбранный вами порт не используется другим процессом или службой в той же системе.
слушайте = 127.0.0.1:3000
Конфигурация PHP-FPM для TCP Socket
Настройка NGINX для работы с сервером приложений PHP-FPM
После того, как вы настроили адрес , который прослушивает PHP-FPM , вам необходимо настроить NGINX на прокси-запрос к нему через этот адрес, используя параметр конфигурации fastcgi_pass
в файле конфигурации блока виртуального сервера.
Например, если файл конфигурации для вашего веб-сайта - /etc/nginx/conf.d/example.com.conf , откройте его для редактирования.
# vim /etc/nginx/conf.d/example.com.conf
Найдите блок location
для обработки файлов .php
и установите параметр fastcgi_pass
следующим образом, если вы настроили PHP-FPM для прослушивания сокета домена UNIX.
fastcgi_pass unix: /run/php/php7.4-fpm.sock # Ubuntu / Debian ИЛИ ЖЕ fastcgi_pass unix: / run / php-fpm / www.носок # CentOS / RHEL / Fedora
Подключите Nginx к PHP-FPM с помощью Unix Socket
Или используйте адрес TCP / IP , если вы настроили PHP-FPM для прослушивания сокета TCP / IP . Если сервер внутренних приложений ( PHP-FPM ) работает на отдельном сервере (замените 10.42.0.10 IP-адресом машины, на которой работает сервер PHP-FPM FastCGI).
fastcgi_pass 10.42.0.10:3000;
Подключите Nginx к PHP-FPM с помощью TCP Socket
Важно : на CentOS 8 , PHP-FPM определен как вышестоящий сервер в файле / etc / nginx / conf.d / php-fpm.conf в блоке восходящего потока с именем php-fpm .
Здесь можно внести соответствующие изменения в зависимости от адреса PHP-FPM , настроенного для прослушивания, в файле конфигурации пула. Конфигурация по умолчанию указывает на сокет домена UNIX.
восходящего потока php-fpm { сервер unix: /run/php-fpm/www.sock; }
Настройте восходящий сервер PHP в Nginx
и в файле блока сервера вашего сайта, просто установите параметр fastcgi_pass
, как показано.
fastcgi_pass php-fpm;
Настройте Nginx на вышестоящий сервер PHP-FPM
После внесения изменений в конфигурации PHP-FPM и NGINX проверьте их синтаксис конфигурации на правильность, как показано ниже.
------------- В Debian и Ubuntu ------------- $ sudo php-fpm -t $ sudo nginx -t ------------- В CentOS / RHEL и Fedora ------------- # php-fpm -t # nginx -t
Хотя выходные данные команды показывают только основной файл конфигурации, все остальные файлы конфигурации также включены и проверены.
Проверьте конфигурацию Nginx и PHP-FPM
Затем вам нужно перезапустить две службы, чтобы изменения вступили в силу, с помощью команды systemctl.
------------- В Debian и Ubuntu ------------- $ sudo systemctl перезапустить nginx $ sudo systemctl перезапустить php7.4-fpm ------------- В CentOS / RHEL и Fedora ------------- # systemctl перезапуск nginx # systemctl перезапуск php-fpm
Если вы получите какие-либо ошибки, вы можете проверить файлы журнала NGINX и PHP-FPM с помощью команды cat.
------------- В Debian и Ubuntu ------------- $ cat /var/log/nginx/error.log $ cat /var/log/php7.4-fpm.log ------------- В CentOS / RHEL и Fedora ------------- $ cat /var/log/nginx/error.log $ cat /var/log/php-fpm/www-error.log
Это все, что у нас было для вас. Раздел комментариев ниже можно использовать, чтобы задавать вопросы. Для получения дополнительной информации см. Документацию NGINX и документацию PHP-FPM.
Асинхронное программирование.Блокирующий ввод-вывод и неблокирующий ввод-вывод - Блог
Это первая публикация из серии, посвященной асинхронному программированию. Вся серия пытается ответить на простой вопрос: «Что такое асинхронность?». Вначале, когда я впервые начал разбираться в вопросе, я думал, что знаю, что это такое. Оказалось, что я ничего не знал об асинхронности. Итак, давайте узнаем!
Всего серий:
В этом посте мы будем говорить о сети, но вы можете легко сопоставить ее с другими операциями ввода / вывода (I / O), например, изменить сокеты на файловые дескрипторы.Кроме того, это объяснение не фокусируется на каком-либо конкретном языке программирования, хотя примеры будут приведены на Python (что я могу сказать - я люблю Python!).
Так или иначе, когда у вас есть вопрос о блокирующих или неблокирующих вызовах, чаще всего это означает работу с вводом-выводом. Наиболее частым случаем в наш век информации, микросервисов и лямбда-функций будет обработка запросов. Сразу можно представить, что вы, дорогой читатель, являетесь пользователем веб-сайта, а ваш браузер (или приложение, в котором вы читаете эти строки) является клиентом.Где-то в глубине Амазонки есть сервер, который обрабатывает ваши входящие запросы и генерирует те же строки, которые вы читаете.
Чтобы начать взаимодействие при таком обмене данными клиент-сервер, клиент и сервер должны сначала установить соединение друг с другом. Мы не будем углубляться в семислойную модель и стек протоколов, участвующих в этом взаимодействии, так как я думаю, что все это можно легко найти в Интернете. Что нам нужно понять, так это то, что с обеих сторон (клиента и сервера) есть специальные точки подключения, известные как сокеты.И клиент, и сервер должны быть привязаны к сокетам друг друга и слушать их, чтобы понимать, что другой говорит на противоположной стороне провода.
В нашем общении сервер что-то делает - либо обрабатывает запрос, преобразует разметку в HTML, либо смотрит, где находятся изображения, он выполняет какую-то обработку.
Если посмотреть на соотношение скорости процессора и скорости сети, разница составляет пару порядков. Оказывается, если наше приложение большую часть времени использует ввод-вывод, в большинстве случаев процессор просто ничего не делает.Этот тип приложения называется с привязкой к вводу-выводу. Для приложений, требующих высокой производительности, это узкое место, и об этом мы поговорим дальше.
Есть два способа организации ввода-вывода (примеры я приведу на основе Linux): с блокировкой и без блокировки .
Также существует два типа операций ввода-вывода: синхронные и асинхронные.
Все вместе они представляют возможные модели ввода / вывода.
Каждая из этих моделей ввода-вывода имеет шаблоны использования, которые выгодны для конкретных приложений.Здесь я продемонстрирую разницу между двумя способами организации ввода-вывода.
Блокировка ввода / вывода
С блокирующим вводом-выводом, когда клиент делает запрос на соединение с сервером, сокет, обрабатывающий это соединение, и соответствующий поток, который читает из него, блокируются до тех пор, пока не появятся некоторые прочитанные данные. Эти данные помещаются в сетевой буфер до тех пор, пока все они не будут прочитаны и не будут готовы к обработке. Пока операция не будет завершена, сервер ничего не может сделать, кроме как ждать .
Самый простой вывод из этого - мы не можем обслуживать более одного соединения в одном потоке. По умолчанию сокеты TCP работают в режиме блокировки.
Простой пример на Python, клиент:
импортная розетка
import sys
время импорта
def main () -> Нет:
host = socket.gethostname ()
порт = 12345
# создать сокет TCP / IP
с socket.socket (socket.AF_INET, socket.SOCK_STREAM) как sock:
в то время как True:
sock.connect ((хост, порт))
в то время как True:
data = str.кодировать (sys.argv [1])
sock.send (данные)
time.sleep (0,5)
если __name__ == "__main__":
assert len (sys.argv)> 1, «Пожалуйста, предоставьте сообщение»
главный()
Здесь мы отправляем сообщение с интервалом 50 мс на сервер в бесконечном цикле. Представьте, что это общение клиент-сервер состоит из загрузки большого файла - для завершения требуется некоторое время.
И сервер:
импортная розетка
def main () -> Нет:
host = socket.gethostname ()
порт = 12345
# создать сокет TCP / IP
с розеткой.socket (socket.AF_INET, socket.SOCK_STREAM) как sock:
# привязываем сокет к порту
sock.bind ((хост, порт))
# прослушивать входящие соединения
sock.listen (5)
print ("Сервер запущен ...")
в то время как True:
conn, addr = sock.accept () # прием входящего соединения, блокировка
print ('Подключено' + str (адрес))
в то время как True:
data = conn.recv (1024) # получение данных, блокировка
если не данные:
перемена
печать (данные)
если __name__ == "__main__":
главный()
Я запускаю это в отдельных окнах терминала с несколькими клиентами как:
$ клиент Python.py "клиент N"
И сервер как:
$ python server.py
Здесь мы просто слушаем сокет и принимаем входящие соединения. Затем мы пытаемся получить данные от этого соединения.
В приведенном выше коде сервер будет заблокирован одним клиентским подключением! Если мы запустим другой клиент с другим сообщением, вы его не увидите. Я настоятельно рекомендую вам поиграть с этим примером, чтобы понять, что происходит.
Что здесь происходит?
Метод send ()
попытается отправить все данные на сервер, в то время как буфер записи на сервере будет продолжать получать данные.Когда вызывается системный вызов для чтения, приложение блокируется, и контекст переключается на ядро. Ядро инициирует чтение - данные передаются в буфер пользовательского пространства. Когда буфер становится пустым, ядро снова пробуждает процесс, чтобы получить следующую порцию данных, подлежащих передаче.
Теперь, чтобы при таком подходе обрабатывать двух клиентов, нам нужно иметь несколько потоков, то есть выделять новый поток для каждого клиентского соединения. Мы скоро вернемся к этому.
Неблокирующий ввод / вывод
Однако есть и второй вариант - неблокирующий ввод / вывод . Отличие очевидно из названия - вместо блокировки любая операция выполняется сразу. Неблокирующий ввод-вывод означает, что запрос немедленно ставится в очередь и функция возвращается. Фактический ввод-вывод обрабатывается позже.
Установив сокет в неблокирующий режим, вы можете эффективно опрашивать его. Если вы попытаетесь читать из неблокирующего сокета и нет данных, он вернет код ошибки ( EAGAIN
или EWOULDBLOCK
).
На самом деле, этот тип опроса - плохая идея. Если вы запустите свою программу в постоянном цикле опроса данных из сокета, это потребует дорогостоящего процессорного времени. Это может быть крайне неэффективным, потому что во многих случаях приложение должно быть занято-ждать, пока данные станут доступны, или пытаться выполнить другую работу, пока команда выполняется в ядре. Более элегантный способ проверить, доступны ли данные для чтения, - использовать select ()
.
Вернемся к нашему примеру с изменениями на сервере:
импорт выбрать
импортный сокет
def main () -> Нет:
хост = сокет.gethostname ()
порт = 12345
# создать сокет TCP / IP
с socket.socket (socket.AF_INET, socket.SOCK_STREAM) как sock:
sock.setblocking (0)
# привязываем сокет к порту
sock.bind ((хост, порт))
# прослушивать входящие соединения
sock.listen (5)
print ("Сервер запущен ...")
# сокетов, из которых мы ожидаем читать
входы = [носок]
выходы = []
в то время как входы:
# ждем, пока хотя бы один из сокетов будет готов к обработке
читаемый, доступный для записи, исключительный = select.выберите (входы, выходы, входы)
для s в читаемом виде:
если s - носок:
conn, addr = s.accept ()
inputs.append (соединение)
еще:
данные = s.recv (1024)
если данные:
печать (данные)
еще:
inputs.remove (s)
s.close ()
если __name__ == "__main__":
главный()
Теперь, если мы запустим этот код с> 1 клиентами, вы увидите, что сервер не заблокирован одним клиентом, и он обрабатывает все, что может быть обнаружено отображаемыми сообщениями.Опять же, я предлагаю вам попробовать этот пример самостоятельно.
Что здесь происходит?
Здесь сервер не ждет, пока все данные будут записаны в буфер. Когда мы делаем сокет неблокирующим, вызывая setblocking (0)
, он никогда не будет ждать завершения операции. Поэтому, когда мы вызываем метод recv
, он вернется в основной поток. Основное механическое отличие состоит в том, что send
, recv
, connect
и accept
могут возвращаться без каких-либо действий.
При таком подходе мы можем одновременно выполнять несколько операций ввода-вывода с разными сокетами из одного и того же потока. Но поскольку мы не знаем, готов ли сокет к операции ввода-вывода, нам пришлось бы задавать каждому сокету один и тот же вопрос и, по сути, вращаться в бесконечном цикле (этот неблокирующий, но все еще синхронный подход называется I / O мультиплексирование).
Чтобы избавиться от этого неэффективного цикла, нам нужен механизм готовности к опросу . В этом механизме мы могли бы опросить готовность всех сокетов, и они могли бы сказать нам, какой из них готов к новой операции ввода-вывода, а какой нет, без явного запроса.Когда любой из сокетов будет готов, мы выполним операции в очереди, а затем сможем вернуться в состояние блокировки, ожидая, пока сокеты будут готовы к следующей операции ввода-вывода.
Существует несколько механизмов готовности к опросу, они разные по производительности и детализации, но обычно детали скрыты «под капотом» и нам не видны.
Ключевые слова для поиска:
Уведомлений:
- Запуск по уровню (состояние)
- Запуск по фронту (состояние изменено)
Механика:
-
выберите ()
,опрос ()
-
epoll ()
,kqueue ()
-
EAGAIN
,EWOULDBLOCK
Многозадачность
Следовательно, наша цель - управлять несколькими клиентами одновременно.Как обеспечить одновременную обработку нескольких запросов?
Есть несколько вариантов:
Отдельные процессы
Самый простой и исторически первый подход - обрабатывать каждый запрос в отдельном процессе. Этот подход удовлетворителен, потому что мы можем использовать тот же API блокирующего ввода-вывода. Если процесс внезапно завершится сбоем, это повлияет только на операции, выполняемые в этом конкретном процессе, а не на какие-либо другие.
Минус - , комплекс связи .Формально между процессами почти нет ничего общего, и любая нетривиальная коммуникация между процессами, которые мы хотим организовать, требует дополнительных усилий по синхронизации доступа и т. Д. Также в любой момент может быть несколько процессов, которые просто ждут клиентских запросов. , а это пустая трата ресурсов.
Давайте посмотрим, как это работает на практике. Как только запускается первый процесс (основной процесс / главный процесс), он генерирует некоторый набор процессов в качестве рабочих. Каждый из них может получать запросы в один и тот же сокет и ждать входящих клиентов.Как только появляется входящее соединение, один из обрабатывающих его процессов принимает это соединение, обрабатывает его от начала до конца, закрывает сокет и затем снова становится готовым для следующего запроса. Возможны варианты - процесс может быть сгенерирован для каждого входящего соединения, или все они могут быть запущены заранее и т. Д. Это может сказаться на производительности, но для нас это сейчас не так важно.
Примеров таких систем:
- Apache
mod_prefork
; - FastCGI для тех, кто чаще всего использует PHP;
- Phusion Passenger для тех, кто пишет на Ruby on Rails;
- PostgreSQL.
Резьба
Другой подход - использовать потоки операционной системы (ОС). В рамках одного процесса мы можем создать несколько потоков. Также можно использовать блокировку ввода-вывода, потому что будет заблокирован только один поток.
Пример:
импорт выбрать
импорт потоковой передачи
импортный сокет
обработчик def (клиент):
в то время как True:
данные = client.recv (1024)
если данные:
печать (данные)
client.close ()
def main () -> Нет:
host = socket.gethostname ()
порт = 12345
# создать сокет TCP / IP
с розеткой.socket (socket.AF_INET, socket.SOCK_STREAM) как sock:
# привязываем сокет к порту
sock.bind ((хост, порт))
# прослушивать входящие соединения
sock.listen (5)
print ("Сервер запущен ...")
в то время как True:
клиент, addr = sock.accept ()
threading.Thread (цель = обработчик, args = (клиент,)). start ()
если __name__ == "__main__":
главный()
Чтобы проверить количество потоков в серверном процессе, вы можете использовать команду linux ps
с PID серверного процесса:
$ ps huH p | туалет -l
Операционная система сама управляет потоками и способна распределять их между доступными ядрами ЦП. Потоки легче процессов . По сути, это означает, что мы можем генерировать больше потоков, чем процессов в одной системе. Мы вряд ли сможем запустить 10 000 процессов, но 10 000 потоков могут быть легкими. Не то, чтобы это было эффективно.
С другой стороны, нет изоляции , т.е. если произойдет какой-либо сбой, это может привести к сбою не только одного конкретного потока, но и всего процесса. И самая большая трудность заключается в том, что память процесса, в котором работают потоки, разделяется между потоками.У нас есть общий ресурс - память, а это значит, что есть необходимость синхронизировать доступ к ней . Хотя проблема синхронизации доступа к общей памяти - это самый простой случай, но, например, может быть подключение к базе данных или пул подключений к базе данных, что является общим для всех потоков внутри приложения, которое обрабатывает входящие подключения.