HTTP 请求

首先,我们看一下这个 HTTP 请求:

  1. 行数 内容
  2. 1 GET /serv/login.php?lang=en&profile=2 HTTP/1.1
  3. 2 Host: www.mydomain.com
  4. 3 User-agent: my small browser
  5. 4 Accept: image/jpeg, image/gif
  6. 5 Accept: image/png

请求行

第一行是请求行,它总是由三部分组成:

  • METHOD:GET
  • URI:/serv/login.php?lang=en&profile=2
  • version tag:HTTP/1.1它们被一个叫 LWS(Linear White Spaces)的标准所分隔,也就是我们常见的空格,不过也可以由制表符或 CR/LF 加上空格/制表符所分隔。

这些方法本身无法包含“:”字符,它只能由字母组成。所有这些增加可描述性的表达形式都是 HAProxy 自行分割,避免了用户去编写复杂而可能不准确的正则表达式来匹配它们。

URI 可以有多种表达形式:

  • 相对 URI:比如/serv/login.php?lang=en&profile=2是一个不含域名的完整 URL,它通常会被服务器、反向代理、透明代理接受。
  • 绝对 URI:比如http://192.168.0.12:8080/serv/login.php?lang=en&profile=2,也称为 URL,它由一种“图式”组成:(协议名称后跟着://)首先是一个域名或地址(有时会加上:后跟着端口号),后面加上/和一个相对 URI。通常一个代理会接受此类形式,支持 HTTP/1.1 的服务器也会接受这种形式。
  • 一个星号(“*”):此形式是不可靠的,仅在和OPTIONS方法联合使用时才会被接受,用于适配查询下一跳。
  • 地址加端口号:比如192.168.0.1:8080,用于CONNECT方法来和一个 HTTP 代理建立 TCP 隧道,通常用于 HTTPS 协议,但也可能是其他协议。在一个相对 URI 中,有两个部分是被确定好的:?前面的部分称为路径(path),通常是服务器上某个静态对象的相对路径;?后面的部分称为查询字符串(query string),大多用来发送GET请求给动态脚本或指定语言、框架、应用程序等。

请求头

从第二行开始就是请求头。它由键名 + : + 组成。传统上,冒号的后面会加上一个 LWS,不过并没有强制要求。

如果请求头有多个键名相同的值,它们可能会被合并到一行,然后用逗号,分隔开多个值,在Cookie:这个键就常见这种情况。如果一个请求头的开头是一个 LWS,那么它可能会跨越多行,本文上面例子的第 4、5 行Accept:就定义了三个值。

与我们通常认知相反的是,请求头的键和值对大小写并不敏感。

请求头中的第一个空行标记头部的结束。很多人认为末尾会有两个 LF,但这种说法不是很准确,尽管两个 LF 确实代表一个合法的空行。

幸运的是,HAProxy 对组合复杂的请求头作了细致的检查、计算和分析,所以我们不用担心请求头会被写成什么样子。但如果一个应用因为用了不寻常的东西而充满 Bug,那指责他也无可厚非。

请注意:

基于 RFC7231 的建议,HAProxy 用 LWS 替换请求头中的换行符来连接多行请求头,这对纠正分析结果、优化 HTTP 解析器效率、简化复杂结构颇有帮助。