предисловие
Протокол HTTP — один из важнейших протоколов в Интернете, хотя он кажется простым, на практике он часто сталкивается с проблемами, и мы сталкивались с ним несколько раз. Существуют длинные соединения и парсинг пакетов. Вы не можете ничего знать о протоколе HTTP, вы должны хорошо его понимать. Поэтому я написал эту серию, чтобы поделиться проблемами и опытом использования протокола HTTP.
Протокол HTTP имеет заголовок и тело как для запроса, так и для ответных пакетов, а тело — это тот ресурс, который вы хотите получить, например, html-страницу, jpeg-изображение, и заголовок используется для создания определённых условностей. Например, клиент и сервер договариваются о форматах передачи, и клиент сначала получает заголовок, знает некоторую информацию о формате, а затем начинает читать основное тело.
Клиент: Accept-Encoding:gzip (сжайте для меня, я использую трафик, сначала скачайте и постепенно распакайте)
Сервер 1: Content-Encoding: null (No Content-Encoding header.) Я не даю компрессии, процессор не бесплатный, хотите ли вы его использовать?
Сервер 2: Content-Encoding:gzip (сохранить трафик, сжать его) Клиент: Connection: keep-alive (Брат, мы наконец-то построили TCP-соединение, будем использовать его в следующий раз)
Сервер 1: Соединение: поддерживать (непросто, продолжать использовать)
Сервер 2: Соединение: закрыто (Кто бы ни продолжил использовать его вместе с вами, наш TCP — одноразовый, и нам придётся снова подключиться, когда мы его найдём) Протокол HTTP не содержит трёх рукопожатий, и когда клиент запрашивает ресурсы у сервера, преимущество имеет серверная сторона. Есть также заголовки без процесса согласования, но сервер напрямую указывает клиенту, что делать. Например, указанная выше длина контента — это то, что сервер сообщает клиенту о размере тела. Но! Официант может не сможет заранее точно сказать размер тела. Сервер должен сначала записать заголовок, а затем тело, если вы хотите записать корпус в заголовок, нужно заранее знать размер тела. Если тело генерируется динамически, сервер завершит работу и начнёт записывать заголовок, что требует больших дополнительных расходов, поэтому в заголовке может не быть длины содержания.
Так как же клиент знает размер тела? Сервер сообщает вам тремя способами.
1. Сервер уже знает размер ресурса и сообщает это через заголовок длины контента.
Content-Length:1076(body的大小是1076B,你读取1076B就可以完成任务了)
Transfer-Encoding: null
2. Сервер не может заранее знать размер ресурса или не желает тратить ресурсы на его расчёт, поэтому он добавляет заголовок в http-ответное сообщение под названием Transfer-Encoding:chunked, что означает передачу блоков. Каждый блок использует фиксированный формат: размер блока спереди, данные за ним, а затем последний блок с размером 0. Таким образом, при парсинге клиенту необходимо обратить внимание на удаление некоторых бесполезных полей.
Content-Length:null
Transfer-Encoding:chunked (接下来的body我要一块一块的传,每一块开始是这一块的大小,等我传到大小为0的块时,就没了)
3. Сервер не знает размера ресурса и не поддерживает режим передачи с фрагментами, поэтому нет ни заголовка с длиной содержания, ни заголовка кодирования передачи. В этот момент заголовок, возвращаемый сервером, должен быть близок.
Content-Length:null
Transfer-Encoding:null
Connection:close(我不知道大小,我也用不了chunked,啥时候我关了tcp连接,就说明传输结束了)
|