HTTP protocol for Web security
2022-9-25 10:19:21 Author: 猫因的安全(查看原文) 阅读量:9 收藏

HTTP 报文


基础

HTTP 请求报文由3部分组成(请求行+请求头+请求体):

下面是一个实际的请求报文 :

  • 「①」 是请求方法,GET 和 POST 是最常见的 HTTP 方法,除此以外还包括 DELETE、HEAD、OPTIONS、PUT、TRACE。不过,当前的大多数浏览器只支持 GET 和 POST,Spring 3.0 提供了一个 HiddenHttpMethodFilter ,允许你通过“_method”的表单参数指定这些特殊的 HTTP 方法(实际上还是通过 POST 提交表单)。服务端配置了 HiddenHttpMethodFilter 后,Spring 会根据 _method 参数指定的值模拟出相应的 HTTP 方法,这样,就可以使用这些 HTTP 方法对处理方法进行映射了。
  • 「②」 为请求对应的 URL 地址,它和报文头的 Host 属性组成完整的请求 URL,
  • 「③」 是协议名称及版本号。
  • 「④」 是 HTTP 的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。
  • 「⑤」 是报文体,它将一个页面表单中的组件值通过 param1=value1&param2=value2 的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求 URL 也可以通过类似于“/chapter15/user.html? param1=value1&param2=value2”的方式传递请求参数。

对照上面的请求报文,我们把它进一步分解,你可以看到一幅更详细的结构图:


HTTP 的响应报文也由三部分组成(响应行+响应头+响应体):

以下是一个实际的 HTTP 响应报文:

  • 「①」 报文协议及版本;
  • 「②」 状态码及状态描述;
  • 「③」 响应报文头,也是由多个属性组成;
  • 「④」 响应报文体,即我们真正要的“干货”。

以下是几个常见的状态码 :

  • 「200 OK」 你最希望看到的,即处理成功!
  • 「303 See Other」  我把你 redirect 到其它的页面,目标的 URL 通过响应报文头的 Location 告诉你。
  • 「304 Not Modified」  告诉客户端,你请求的这个资源至你上次取得后,并没有更改,你直接用你本地的缓存吧,我很忙哦,你能不能少来烦我啊!
  • 「404 Not Found」  你最不希望看到的,即找不到页面。如你在 google 上找到一个页面,点击这个链接返回 404,表示这个页面已经被网站删除了,google 那边的记录只是美好的回忆。
  • 「500 Internal Server Error」  看到这个错误,你就应该查查服务端的日志了,肯定抛出了一堆异常,别睡了,起来改 BUG 去吧!

更多关于状态码参考 HTTP状态码


请求方法


根据 HTTP 标准,HTTP 请求可以使用多种请求方法。

HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法。

HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。

  • GET : 请求指定的页面信息,并返回实体主体。
  • HEAD : 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
  • POST : 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。
  • PUT : 从客户端向服务器传送的数据取代指定的文档的内容。
  • DELETE : 请求服务器删除指定的页面。
  • CONNECT : HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
  • OPTIONS : 允许客户端查看服务器的性能。
  • TRACE : 回显服务器收到的请求,主要用于测试或诊断。
  • PATCH : 是对 PUT 方法的补充,用来对已知资源进行局部更新 。

HTTP headers

「Source & Reference」

  • HTTP头部详解
  • HTTP 响应头信息
  • HTTP 请求头中的 X-Forwarded-For
  • List of HTTP header fields

通常 HTTP 消息包括客户机向服务器的请求消息和服务器向客户机的响应消息。这两种类型的消息由一个起始行,一个或者多个头域,一个只是头域结束的空行和可选的消息体组成。HTTP 的头域包括通用头,请求头,响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。域名是大小写无关的,域值前可以添加任何数量的空格符,头域可以被扩展为多行,在每行开始处,使用至少一个空格或制表符。

通用头域

通用头域包含请求和响应消息都支持的头域,通用头域包含 Cache-ControlConnectionDatePragmaTransfer-EncodingUpgradeVia。对通用头域的扩展要求通讯双方都支持此扩展,如果存在不支持的通用头域,一般将会作为实体头域处理。下面简单介绍几个在 UPnP 消息中使用的通用头域。

「Cache-Control 头域」

Cache -Control 指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置 Cache-Control 并不会修改另一个消息处理过程中的缓存处理过程。

请求时的缓存指令包括 no-cacheno-storemax-agemax-stalemin-freshonly-if-cached

响应消息中的指令包括

  • Public 指示响应可被任何缓存区缓存;
  • Private 指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效;
  • no-cache 指示请求或响应消息不能缓存;
  • no-store 用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存;
  • max-age 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应;
  • min-fresh 指示客户机可以接收响应时间小于当前时间加上指定时间的响应;
  • max-stale 指示客户机可以接收超出超时期间的响应消息。如果指定 max-stale 消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

「Date 头域」

date 头域表示消息发送的时间,时间的描述格式由 rfc822 定义。例如,Date:Mon,31Dec200104:25:57GMT。Date 描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。

「Pragma 头域」

Pragma 头域用来包含实现特定的指令,最常用的是 Pragma:no-cache。在 HTTP/1.1 协议中,它的含义和 Cache-Control:no-cache 相同。

「Connection 头域」

Connection 表示连接状态

  • 请求

    close(告诉 WEB 服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了)。
    keepalive(告诉 WEB 服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求)。
  • 响应

    close(连接已经关闭)。
    Keep-Alive:如果浏览器请求保持连接,则该头部表明希望 WEB 服务器保持连接多长时间(秒)。例如:Keep-Alive:300

请求消息(请求头)

请求消息的第一行为下面的格式:Method Request-URI HTTP-Version

  • Method 表示对于 Request-URI 完成的方法,这个字段是大小写敏感的,包括 OPTIONSGETHEADPOSTPUTDELETETRACE。方法 GETHEAD 应该被所有的通用 WEB 服务器支持,其他所有方法的实现是可选的,GET 方法取回由 Request-URI 标识的信息,
  • HEAD 方法也是取回由 Request-URI 标识的信息,只是可以在响应时,不返回消息体;
  • POST 方法可以请求服务器接收包含在请求中的实体信息,可以用于提交表单,向新闻组、BBS、邮件群组和数据库发送消息。
  • Request-URI 表示请求的URL。Request-URI 遵循 URI 格式,在此字段为星号(*)时,说明请求并不用于某个特定的资源地址,而是用于服务器本身。
  • HTTP- Version 表示支持的 HTTP 版本,例如为 HTTP/1.1

请求头域允许客户端向服务器传递关于请求或者关于客户机的附加信息。请求头域可能包含下列字段 AcceptAccept-CharsetAccept-EncodingAccept-LanguageAuthorizationFromHostIf-Modified-SinceIf-MatchIf-None-MatchIf-RangeIf-Unmodified-SinceMax-ForwardsProxy-AuthorizationRangeRefererUser-Agent。对请求头域的扩展要求通讯双方都支持,如果存在不支持的请求头域,一般将会作为实体头域处理。

典型的请求消息

GET http://download.microtool.de:80/somedata.exe
Host: download.microtool.de
Accept:*/*
Pragma: no-cache
Cache-Control: no-cache
Referer: http://download.microtool.de/
User-Agent:Mozilla/4.04[en](Win95;I;Nav)
Range:bytes=554554-

上例第一行表示 HTTP 客户端(可能是浏览器、下载程序)通过 GET 方法获得指定 URL 下的文件。

  • Host头域指定请求资源的 Intenet 主机和端口号,必须表示请求 url 的原始服务器或网关的位置。HTTP/1.1 请求必须包含主机头域,否则系统会以 400 状态码返回;

  • Accept:告诉 WEB 服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type。

  • Accept-Charset: 浏览器申明自己接收的字符集。

  • Authorization:当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时,用该头部来回应自己的身份验证信息给 WEB 服务器。

  • Range

    表示头500个字节:bytes=0-499
    表示第二个500字节:bytes=500-999
    表示最后500个字节:bytes=-500
    表示500字节以后的范围:bytes=500-
    第一个和最后一个字节:bytes=0-0,-1
    同时指定几个范围:bytes=500-600,601-999

    但是服务器可以忽略此请求头,如果无条件 GET 包含 Range 请求头,响应会以状态码 206(PartialContent)返回而不是以 200 (OK)


响应消息(响应头)

响应信息如内容类型,类型的长度,服务器信息,设置 Cookie

响应消息的第一行为下面的格式:HTTP-Version Status-Code Reason-Phrase

  • HTTP -Version 表示支持的 HTTP 版本,例如为 HTTP/1.1。

  • Status-Code 是一个三个数字的结果代码。

    Status-Code 主要用于机器自动识别,Reason-Phrase 主要用于帮助用户理解。Status-Code 的第一个数字定义响应的类别,后两个数字没有分类的作用。第一个数字可能取5个不同的值
    • 1xx : 信息响应类,表示接收到请求并且继续处理
    • 2xx : 处理成功响应类,表示动作被成功接收、理解和接受
    • 3xx : 重定向响应类,为了完成指定的动作,必须接受进一步处理
    • 4xx : 客户端错误,客户请求包含语法错误或者是不能正确执行
    • 5xx : 服务端错误,服务器不能正确执行一个正确的请求
  • Reason-Phrase 给 Status-Code 提供一个简单的文本描述。

响应头域允许服务器传递不能放在状态行的附加信息,这些域主要描述服务器的信息和 Request-URI 进一步的信息。响应头域包含 AgeLocationProxy-AuthenticatePublicRetry-AfterServerVaryWarningWWW-Authenticate。对响应头域的扩展要求通讯双方都支持,如果存在不支持的响应头 域,一般将会作为实体头域处理。

典型的响应消息:

HTTP/1.0 200 OK
Date:Mon,31Dec200104:25:57MGT
Server:Apache/1.3.14(Unix)
Content-type:text/html
Last-modified:Tue,17Apr200106:46:28GMT
Etag:"a030f020ac7c01:1e9f"
Content-length:39725426
Content-range:bytes554554-40279979/40279980

Location 响应头用于重定向接收者到一个新 URI 地址。Server 响应头包含处理请求的原始服务器的软件信息。此域能包含多个产品标识和注释,产品标识一般按照重要性排序


实体消息(实体头和实体)

请求消息和响应消息都可以包含实体信息,实体信息一般由实体头域和实体组成。

实体头域包含关于实体的原信息,实体头包括 AllowContent-BaseContent-EncodingContent-LanguageContent-LengthContent-LocationContent-MD5Content-RangeContent-TypeEtagExpiresLast-Modifiedextension-headerextension-header 允许客户端定义新的实体头,但是这些域可能无法为接受方识别。

  • Content-Type 实体头用于向接收方指示实体的介质类型,指定 HEAD 方法送到接收方的实体介质类型,或 GET 方法发送的请求介质类型,表示后面的文档属于什么 MIME 类型。

  • Content-Length 表示实际传送的字节数。

  • Allow 实体头至服务器支持哪些请求方法(如 GET、POST 等)。

  • Content-Range 表示传送的范围,用于指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。

    一般格式:Content-Range:bytes-unitSPfirst-byte-pos-last-byte-pos/entity-legth

    例如,传送头500个字节次字段的形式:Content-Range:bytes0-499/1234 如果一个 http 消息包含此节(例如,对范围请求的响应或对一系列范围的重叠请求)。

  • Content-Encoding 指文档的编码(Encode)方法。实体可以是一个经过编码的字节流,它的编码方式由 Content-Encoding 或 Content-Type 定义,它的长度由 Content-Length 或 Content-Range 定义。


「X-Forwarded-For」

通过名字就知道,X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。

X-Forwarded-For 请求头格式非常简单,就这样:

X-Forwarded-For: client, proxy1, proxy2

可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。

如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:

X-Forwarded-For: IP0, IP1, IP2

Proxy3 直连服务器,它会给 XFF 追加 IP2,表示它是在帮 Proxy2 转发请求。列表中并没有 IP3,IP3 可以在服务端通过 Remote Address 字段获得。我们知道 HTTP 连接基于 TCP 连接,HTTP 协议中没有 IP 的概念,Remote Address 来自 TCP 连接,表示与服务端建立 TCP 连接的设备 IP,在这个例子里就是 IP3。

Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。不同语言获取 Remote Address 的方式不一样,例如 php 是 $_SERVER["REMOTE_ADDR"],Node.js 是 req.connection.remoteAddress,但原理都一样。


实例

「HTTP 请求消息头部实例」

Host:rss.sina.com.cn
User-Agent:Mozilla/5、0 (Windows; U; Windows NT 5、1; zh-CN; rv:1、8、1、14) Gecko/20080404 Firefox/2、0、0、14
Accept:text/xml,application/xml,application/xhtml+xml,text/html;q=0、9,text/plain;q=0、8,image/png,*/*;q=0、5
Accept-Language:zh-cn,zh;q=0、5
Accept-Encoding:gzip,deflate
Accept-Charset:gb2312,utf-8;q=0、7,*;q=0、7
Keep-Alive:300
Connection:keep-alive
Cookie:userId=C5bYpXrimdmsiQmsBPnE1Vn8ZQmdWSm3WRlEB3vRwTnRtW <- Cookie
If-Modified-Since:Sun, 01 Jun 2008 12:05:30 GMT
Cache-Control:max-age=0

「HTTP 响应消息头部实例」

Status:OK - 200                                        <- 响应状态码,表示 web 服务器处理的结果。
Date:Sun, 01 Jun 2008 12:35:47 GMT
Server:Apache/2、0、61 (Unix)
Last-Modified:Sun, 01 Jun 2008 12:35:30 GMT
Accept-Ranges:bytes
Content-Length:18616
Cache-Control:max-age=120
Expires:Sun, 01 Jun 2008 12:37:47 GMT
Content-Type:application/xml
Age:2
X-Cache:HIT from 236-41、D07071951、sina、com、cn <- 反向代理服务器使用的 HTTP 头部
Via:1.0 236-41.D07071951.sina.com.cn:80 (squid/2.6.STABLE13)
Connection:close

头部详解

「Accept」

告诉 WEB 服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type

「Accept-Charset」

浏览器申明自己接收的字符集

「Accept-Encoding」

浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)

「Accept-Language」

浏览器申明自己接收的语言,语言跟字符集的区别:中文是语言,中文有多种字符集,比如 big5,gb2312,gbk 等等。

「Age」

当代理服务器用自己缓存的实体去响应请求时,用该头部表明该实体从产生到现在经过多长时间了。

「Authorization」

当客户端接收到来自 WEB 服务器的 WWW-Authenticate 响应时,用该头部来回应自己的身份验证信息给 WEB 服务器。

「Cache-Control」

请求:no-cache(不要缓存的实体,要求现在从WEB服务器去取) max-age:(只接受 Age 值小于 max-age 值,并且没有过期的对象) max-stale:(可以接受过去的对象,但是过期时间必须小于 max-stale 值)

「min-fresh」

(接受其新鲜生命期大于其当前 Age 跟 min-fresh 值之和的缓存对象)响应:public(可以用 Cached 内容回应任何用户) private(只能用缓存内容回应先前请求该内容的那个用户) no-cache(可以缓存,但是只有在跟 WEB 服务器验证了其有效后,才能返回给客户端) max-age:(本响应包含的对象的过期时间) ALL: no-store(不允许缓存)

「Connection」

请求:close(告诉 WEB 服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了)。keepalive(告诉 WEB 服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求)。

「Content-Disposition」

在常规的 HTTP 应答中,Content-Disposition 响应头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。在 multipart/form-data 类型的应答消息体中,Content-Disposition 消息头可以被用在 multipart 消息体的子部分中,用来给出其对应字段的相关信息。各个子部分由在 Content-Type 中定义的分隔符分隔。用在消息体自身则无实际意义。

Content-Disposition 消息头最初是在 MIME 标准中定义的,HTTP 表单及 POST 请求只用到了其所有参数的一个子集。只有 form-data 以及可选的 name 和 filename 三个参数可以应用在 HTTP 场景中。

  • 指令

    • name

      后面是一个表单字段名的字符串,每一个字段名会对应一个子部分。在同一个字段名对应多个文件的情况下(例如,带有 multiple 属性的 <input type=file> 元素),则多个子部分共用同一个字段名。如果 name 参数的值为 _charset_ ,意味着这个子部分表示的不是一个 HTML 字段,而是在未明确指定字符集信息的情况下各部分使用的默认字符集。

    • filename

      后面是要传送的文件的初始名称的字符串。这个参数总是可选的,而且不能盲目使用:路径信息必须舍掉,同时要进行一定的转换以符合服务器文件系统规则。这个参数主要用来提供展示性信息。当与 Content-Disposition: attachment 一同使用的时候,它被用作"保存为"对话框中呈现给用户的默认文件名。

    • filename*

      filenamefilename* 两个参数的唯一区别在于,filename* 采用了  RFC 5987 中规定的编码方式。当 filenamefilename* 同时出现的时候,应该优先采用 filename*,假如二者都支持的话。

  • 作为消息主体中的消息头

    在 HTTP 场景中,第一个参数或者是 inline(默认值,表示回复中的消息体会以页面的一部分或者整个页面的形式展示),或者是 attachment(意味着消息体应该被下载到本地;大多数浏览器会呈现一个“保存为”的对话框,将 filename 的值预填为下载后的文件名,假如它存在的话)。

    Content-Disposition: inline
    Content-Disposition: attachment
    Content-Disposition: attachment; filename="filename.jpg"
  • 作为 multipart body 中的消息头

    在 HTTP 场景中。第一个参数总是固定不变的 form-data;附加的参数不区分大小写,并且拥有参数值,参数名与参数值用等号 = 连接,参数值用双引号括起来。参数之间用分号 ; 分隔。

    Content-Disposition: form-data
    Content-Disposition: form-data; name="fieldName"
    Content-Disposition: form-data; name="fieldName"; filename="filename.jpg"

「Content-Encoding」

WEB 服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象。例如:Content-Encoding:gzip

「Content-Language」

WEB 服务器告诉浏览器自己响应的对象的语言。

「Content-Length」

WEB 服务器告诉浏览器自己响应的对象的长度。例如:Content-Length: 26012

「Content-Range」

WEB 服务器表明该响应包含的部分对象为整个对象的哪个部分。例如:Content-Range: bytes 21010-47021/47022

「Content-Type」

WEB 服务器告诉浏览器自己响应的对象的类型。例如:Content-Type:application/xml

「ETag」

就是一个对象(比如 URL)的标志值,就一个对象而言,比如一个 html 文件,如果被修改了,其 Etag 也会别修改,所以 ETag 的作用跟 Last-Modified 的作用差不多,主要供 WEB 服务器判断一个对象是否改变了。比如前一次请求某个 html 文件时,获得了其 ETag,当这次又请求这个文件时,浏览器就会把先前获得的 ETag 值发送给WEB 服务器,然后 WEB 服务器会把这个 ETag 跟该文件的当前 ETag 进行对比,然后就知道这个文件有没有改变了。

「Expired」

WEB 服务器表明该实体将在什么时候过期,对于过期了的对象,只有在跟 WEB 服务器验证了其有效性后,才能用来响应客户请求。是 HTTP/1.0 的头部。例如:Expires:Sat, 23 May 2009 10:02:12 GMT

「Host」

客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。例如:Host:rss.sina.com.cn

「If-Match」

如果对象的 ETag 没有改变,其实也就意味著对象没有改变,才执行请求的动作。

「If-None-Match」

如果对象的 ETag 改变了,其实也就意味著对象也改变了,才执行请求的动作。

「If-Modified-Since」

如果请求的对象在该头部指定的时间之后修改了,才执行请求的动作(比如返回对象),否则返回代码304,告诉浏览器该对象没有修改。例如:If-Modified-Since:Thu,10 Apr 2008 09:14:42 GMT

「If-Unmodified-Since」

如果请求的对象在该头部指定的时间之后没修改过,才执行请求的动作(比如返回对象)

「If-Range」

浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,如果对象改变了,就把整个对象给我。浏览器通过发送请求对象的 ETag 或者自己所知道的最后修改时间给 WEB 服务器,让其判断对象是否改变了。总是跟 Range 头部一起使用。

「Last-Modified」

WEB 服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等等。例如:Last-Modified:Tue, 06 May 2008 02:42:43 GMT

「Location」

WEB 服务器告诉浏览器,试图访问的对象已经被移到别的位置了,到该头部指定的位置去取。例如:Location http://i0.sinaimg.cn/dy/deco/2008/0528/sina0.gif Location 通常不是直接设置的,而是通过 HttpServletResponse 的 sendRedirect 方法,该方法同时设置状态代码为 302。

「Pramga」

主要使用 Pramga: no-cache,相当于 Cache-Control: no-cache。例如:Pragma:no-cache

「Proxy-Authenticate」

代理服务器响应浏览器,要求其提供代理身份验证信息。

「Proxy-Authorization」

浏览器响应代理服务器的身份验证请求,提供自己的身份信息。

「Range」

浏览器(比如 Flashget 多线程下载时)告诉 WEB 服务器自己想取对象的哪部分。例如:Range:bytes=1173546-

「Referer」

浏览器向 WEB 服务器表明自己是从哪个网页/URL 获得/点击当前请求中的网址/URL。例如:Referer:http://www.sina.com/

「Server」

WEB 服务器表明自己是什么软件及版本等信息。例如:Server:Apache/2.0.61 (Unix)

「User-Agent」

浏览器表明自己的身份(是哪种浏览器)。 例如:User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.14) Gecko/20080404 Firefox/2、0、0、14

「Transfer-Encoding」

WEB 服务器表明自己对本响应消息体(不是消息体里面的对象)作了怎样的编码,比如是否分块(chunked)。例如:Transfer-Encoding:chunked

「Vary」

WEB 服务器用该头部的内容告诉 Cache 服务器,在什么条件下才能用本响应所返回的对象响应后续的请求。假如源WEB服务器在接到第一个请求消息时,其响应消息的头部为: Content-Encoding: gzip; Vary: Content-Encoding 那么 Cache 服务器会分析后续请求消息的头部,检查其 Accept-Encoding,是否跟先前响应的 Vary 头部值一致,即是否使用相同的内容编码方法,这样就可以防止 Cache 服务器用自己 Cache 里面压缩后的实体响应给不具备解压能力的浏览器。例如:Vary:Accept-Encoding

「Via」

列出从客户端到 OCS 或者相反方向的响应经过了哪些代理服务器,他们用什么协议(和版本)发送的请求。当客户端请求到达第一个代理服务器时,该服务器会在自己发出的请求里面添加 Via 头部,并填上自己的相关信息,当下一个代理服务器收到第一个代理服务器的请求时,会在自己发出的请求里面复制前一个代理服务器的请求的 Via 头部,并把自己的相关信息加到后面,以此类推,当 OCS 收到最后一个代理服务器的请求时,检查 Via 头部,就知道该请求所经过的路由。例如:Via:1.0 236.D0707195.sina.com.cn:80 (squid/2.6.STABLE13)

「Refresh」

表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过 setHeader("Refresh", "5; URL=http://host/path") 让浏览器读取指定的页面。注意这种功能通常是通过设置 HTML 页面 HEAD 区的 <META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path"> 实现,这是因为,自动刷新或重定向对于那些不能使用 CGI或  Servlet 的 HTML 编写者十分重要。但是,对于 Servlet 来说,直接设置 Refresh 头更加方便。注意 Refresh 的意义是"N 秒之后刷新本页面或访问指定页面",而不是"每隔N秒刷新本页面或访问指定页面"。因此,连续刷新要求每次都发送一个 Refresh 头,而发送 204 状态代码则可以阻止浏览器继续刷新,不管是使用 Refresh 头还是 <META HTTP-EQUIV="Refresh" ...>。注意 Refresh 头不属于 HTTP 1.1 正式规范的一部分,而是一个扩展,但 Netscape 和 IE 都支持它。

「Set-Cookie」

设置和页面关联的 Cookie。Servlet 不应使用 response.setHeader("Set-Cookie", ...) ,而是应使用 HttpServletResponse 提供的专用方法 addCookie。

「Server」

服务器名字。Servlet 一般不设置这个值,而是由 Web 服务器自己设置。

「WWW-Authenticate」

客户应该在 Authorization 头中提供什么类型的授权信息?在包含 401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"") 。注意 Servlet 一般不进行这方面的处理,而是让 Web 服务器的专门机制来控制受密码保护页面的访问(例如 .htaccess)。


POST 请求数据提交格式

服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说到 POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分。

快到中午了,张三丰不想去食堂吃饭,于是打电话叫外卖:老板,我要一份[鱼香肉丝],要 12:30 之前给我送过来哦,我在江湖湖公司研发部,叫张三丰。

这里,你要[鱼香肉丝]相当于 HTTP 报文体,而“12:30之前送过来”,你叫“张三丰”等信息就相当于 HTTP 的请求头。它们是一些附属信息,帮忙你和饭店老板顺利完成这次交易。

「application/x-www-form-urlencoded」

最基本的 form 表单结构,用于传递字符参数的键值对,请求结构如下

POST  HTTP/1.1
Host: www.demo.com
Cache-Control: no-cache
Postman-Token: 81d7b315-d4be-8ee8-1237-04f3976de032
Content-Type: application/x-www-form-urlencoded

key=value&testKey=testValue

请求头中的 Content-Type 设置为 application/x-www-form-urlencoded; 提交的的数据,请求 body 中按照 key1=value1&key2=value2 进行编码,key 和 value 都要进行 urlEncode;

「multipart/form-data」

这是上传文件时,最常见的数据提交方式,看一下请求结构

POST  HTTP/1.1
Host: www.demo.com
Cache-Control: no-cache
Postman-Token: 679d816d-8757-14fd-57f2-fbc2518dddd9
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="key"

value
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="testKey"

testValue
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="imgFile"; filename="no-file"
Content-Type: application/octet-stream

<data in here>
------WebKitFormBoundary7MA4YWxkTrZu0gW--

首先请求头中的 Content-Type 是 multipart/form-data; 并且会随机生成 一个 boundary, 用于区分请求 body 中的各个数据; 每个数据以 --boundary 开始, 紧接着换行,下面是内容描述信息, 接着换2行, 接着是数据; 然后以 --boundary-- 结尾, 最后换行;

文本数据和文件,图片的内容描述是不相同的 文本参数:

Content-Disposition: form-data; name="key"
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

文件参数:

Content-Disposition: form-data; name="imgFile"; filename="no-file"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary

Source & Reference

  • HTTP请求行、请求头、请求体详解
  • Content-Disposition

Connection


「Connection 的作用」

此 header 的 含义是当 client 和 server 通信时对于长链接如何进行处理。

「Connection: close 的作用」

有的网站会在服务器运行一段时间后 down 掉,有很多原因可能造成这种现象:比如 tomcat 堆和非堆内存设置不足,程序没能释放内存空间造成内存溢出,或者某些进程一直运行没能释放,造成 cup 资源大量消耗。

但除了程序本身的原因,还有可能是客服端访问造成(当然这个客户端也包含如蜘蛛软件等搜索引擎),如果服务器和客户端建立的是长链接 (可以用 "netstat -a" 命令查看网络访问信息),这就需要对 http 响应头的 connection 做一定的设置。

「Connection: keep-alive 的作用」

如果你用过 Mysql,应该知道 Mysql 的连接属性中有一个与 KeepAlive 类似的 Persistent Connection,即:长连接 (PConnect)。该属性打开的话,可以使一次 TCP 连接为同一用户的多次请求服务,提高了响应速度。

「Connection: close 和 keep-alive 的区别」

KeepAlive=On 时,每次用户访问,打开一个 TCP 连接,Apache 都会保持该连接一段时间,以便该连接能连续为同一 client 服务,在 KeepAliveTimeOut 还没到期并且 MaxKeepAliveRequests 还没到阈值之前,Apache 必然要有一个 httpd 进程来维持该连接,httpd 进程不是廉价的,他要消耗内存和 CPU 时间片的。假如当前 Apache 每秒响应 100 个用户访问,KeepAliveTimeOut=5,此时 httpd 进程数就是 100x5=500 个 (prefork 模式),一个 httpd 进程消耗 5M 内存的话,就是 500x5M=2500M=2.5G,夸张吧?当然,Apache 与 Client 只进行了 100 次 TCP 连接。如果你的内存够大,系统负载不会太高,如果你的内存小于 2.5G,就会用到 Swap,频繁的 Swap 切换会加重 CPU 的 Load。

现在我们关掉 KeepAlive ,Apache 仍然每秒响应 100 个用户访问,因为我们将图片、js、css 等分离出去了,每次访问只有 1 个 request,此时 httpd 的进程数是 100x1=100 个,使用内存 100x5M=500M,此时 Apache 与 Client 也是进行了 100 次 TCP 连接。性能却提升了太多。

「如何选择」

当你的 Server 内存充足时,KeepAlive =On 还是 Off 对系统性能影响不大。

当你的 Server 上静态网页 (Html、图片、Css、Js) 居多时,建议打开 KeepAlive。

当你的 Server 多为动态请求(因为连接数据库,对文件系统访问较多),KeepAlive 关掉,会节省一定的内存,节省的内存正好可以作为文件系统的 Cache(vmstat 命令中 cache 一列),降低 I/O 压力。

当 KeepAlive=On 时,KeepAliveTimeOut 的设置其实也是一个问题,设置的过短,会导致 Apache 频繁建立连接,给 Cpu 造成压力,设置的过长,系统中就会堆积无用的 Http 连接,消耗掉大量内存,具体设置多少,可以进行不断的调节,因你的网站浏览和服务器配置而异。


Source & Reference

  • Connection: close和keep-alive之间的区别
  • 关于设置http响应头connection的作用

Vary


Vary 的作用

Vary 一般出现在 HTTP 请求的响应信息头部,比如像下面这样

HTTP/1.0 200 OK
Date: Fri, 24 Sep 2010 23:09:32 GMT
Content-Type: application/json;charset=UTF-8
Content-Language: en-US
Vary: Accept-Encoding,User-Agent
Age: 1235
X-Cache: HIT from cache.kolich.local
X-Cache-Lookup: HIT from cache.kolich.local:80
Content-Length: 25090
Connection: close

或者是这样

HTTP/1.1 200 OK
Server: nginx
Date: Tue, 31 Dec 2013 16:34:48 GMT
Content-Type: application/x-javascript
Content-Length: 66748
Last-Modified: Tue, 31 Dec 2013 14:30:52 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: "52c2d51c-104bc"
Expires: Fri, 29 Dec 2023 16:34:48 GMT
Cache-Control: max-age=315360000
Strict-Transport-Security: max-age=31536000
Accept-Ranges: bytes

「Vary 出现在响应信息中的作用是什么呢?」

首先这是由服务器端添加,添加到响应头部。大部分情况下是用在客户端缓存机制或者是缓存服务器在做缓存操作的时候,会使用到 Vary 头,会读取响应头中的 Vary 的内容,进行一些缓存的判断。

对于服务器提供的某个接口来说,有时候会出现不同种类的客户端对其进行网络请求获取数据,不同的客户端可能支持的压缩编码方式不同,可能有的客户端不支持压缩,那么服务器端返回的数据就不能压缩,有的支持 gzip 编码,那么服务器端就可以进行 gzip 编码返回给客户端,客户端获取到数据之后,做响应的 gzip 解码。还有种情况,对于不同的客户端,需要的内容不一样,比如针对特定,浏览器要求输出的内容不一样,比如在 IE6 浏览器上要输出不一样的内容,这就需要服务器端做不同的数据返回。所以说,服务器提供的同一个接口,客户端进行同样的网络请求,对于不同种类的客户端可能需要的数据不同,服务器端的返回方式返回数据也会不同。对于这个问题的解决,我们可以在请求信息添加 Accept-Encoding、User-Agent 等头部。

这些都没有问题,顺利的解决了我们上面提出的问题,然而,当使用到缓存的时候,就会有问题,比如要求针对 IE5 和 IE6 显示不同的数据,针对同一接口的同样的请求,缓存服务器中分别存储了 IE5 和 IE6 两份数据,由于同样的接口同样的请求,一旦服务器判定要从缓存中获取数据的话,很有可能会导致两个客户端的请求拿到同一份数据,这就会让那个数据展示出现问题;再比如说A类客户端支持压缩格式 gzip,B 类客户端不支持压缩,对于同一个接口同样的请求,如果服务器端打算从缓存服务器中取出数据返回的话,A、B 两类客户端可能会收到同样的数据,这样要就会导致编解码出错。

这时候我们的 Vary 响应头就登场了,Vary 的字面意思是“不一、多样化”,顾名思义,它的存在区分同样的网络请求的不同之处,其实就是通过头部信息来区分。

一个简单的 Vary 头包括:

Vary: Accept-Encoding

Vary: Accept-Encoding,User-Agent

Vary: X-Some-Custom-Header,Host

Vary: *

Vary 存在于响应头中,它的内容来自于请求头中相关字段,Vary 头的内容如果是多条则用 , 分割。缓存服务器会将某接口的首次请求结果缓存下来(包括响应头中的 Vary),后面在发生相同请求的时候缓存服务器会拿着缓存的 Vary 来进行判断。比如 Vary: Accept-Encoding,User-Agent,那么 Accept-Encoding 与 User-Agent 两个请求头的内容,就会作为判断是否返回缓存数据的依据,当缓存服务器中相同请求的缓存数据的编码格式、代理服务与当前请求的编码格式、代理服务一致,那就返回缓存数据,否则就会从服务器重新获取新的数据。当缓存服务器中已经缓存了该条请求,那么某次服务器端的响应头中如果 Vary 的值改变,则 Vary 会更新到该请求的缓存中去,下次请求会对比新的 Vary 内容。

官方解释Vary头:

告知下游的代理服务器,应当如何对以后的请求协议头进行匹配,以决定是否可使用已缓存的响应内容而不是重新从原服务器请求新的内容。


Source & Reference

  • HTTP请求的响应头部Vary的理解

文章来源: http://mp.weixin.qq.com/s?__biz=Mzk0NjMyNDcxMg==&mid=2247496707&idx=1&sn=246eeaf448045719cb475bb9904f7a60&chksm=c3056184f472e8925d139d0ab77713aa413d15c050cc36e3b9154faebb5621ccd7817c849049#rd
如有侵权请联系:admin#unsafe.sh