上一篇博客:ASP.net 获得客户端的IP相关知识 中我提到了,如果你想编码更改 HTTP_VIA、HTTP_X_FORWARDED_FOR 的值,你需要客户端增加的HTTP Head为:VIA、X_FORWARDED_FOR。即,少个 "HTTP_" 前缀。那么,到底读取这些值时,那些HTTP头增加时候需要增加HTTP_前缀,那些又不需要呢?
简单来说,出了一些系统预先定义的,有特殊意义的HTTP头外,其他都需要增加 "HTTP_" 前缀。这是W3C 的 The Common Gateway Interface (CGI) 规范的定义。这些预定义的变量如下:
变量 | 说明 |
APPL_MD_PATH | 检索 ISAPI DLL 的 (WAM) Application 的元数据库路径。 |
APPL_PHYSICAL_PATH | 检索与元数据库路径相应的物理路径。IIS 通过将 APPL_MD_PATH 转换为物理(目录)路径以返回值。 |
AUTH_PASSWORD | 该值输入到客户端的鉴定对话中。只有使用基本鉴定时,该变量才可用。 |
AUTH_TYPE | 这是用户访问受保护的脚本时,服务器用于检验用户的验证方法。 |
AUTH_USER | 未被鉴定的用户名。 |
CERT_COOKIE | 客户端验证的唯一 ID,以字符串方式返回。可作为整个客户端验证的签字。 |
CERT_FLAGS | 如有客户端验证,则 bit0 为 1。 |
CERT_ISSUER | 用户验证中的颁布者字段(O=MS,OU=IAS,CN=user name,C=USA)。 |
CERT_KEYSIZE | 安全套接字层连接关键字的位数,如 128。 |
CERT_SECRETKEYSIZE | 服务器验证私人关键字的位数。如 1024。 |
CERT_SERIALNUMBER | 用户验证的序列号字段。 |
CERT_SERVER_ISSUER | 服务器验证的颁发者字段。 |
CERT_SERVER_SUBJECT | 服务器验证的主字段。 |
CERT_SUBJECT | 客户端验证的主字段。 |
CONTENT_LENGTH | 客户端发出内容的长度。 |
CONTENT_TYPE | 内容的数据类型。同附加信息的查询一起使用,如 HTTP 查询 GET、 POST 和 PUT。 |
GATEWAY_INTERFACE | 服务器使用的 CGI 规格的修订。格式为 CGI/revision。 |
HTTPS | 如果请求穿过安全通道(SSL),则返回 ON。如果请求来自非安全通道,则返回 OFF。 |
HTTPS_KEYSIZE | 安全套接字层连接关键字的位数,如 128。 |
HTTPS_SECRETKEYSIZE | 服务器验证私人关键字的位数。如 1024。 |
HTTPS_SERVER_ISSUER | 服务器验证的颁发者字段。 |
HTTPS_SERVER_SUBJECT | 服务器验证的主字段。 |
INSTANCE_ID | 文本格式 IIS 实例的 ID。如果实例 ID 为 1,则以字符形式出现。使用该变量可以检索请求所属的(元数据库中)Web 服务器实例的 ID。 |
INSTANCE_META_PATH | 响应请求的 IIS 实例的元数据库路径。 |
LOCAL_ADDR | 返回接受请求的服务器地址。如果在绑定多个 IP 地址的多宿主机器上查找请求所使用的地址时,这条变量非常重要。 |
LOGON_USER | 用户登录 Windows NT® 的帐号。 |
PATH_INFO | 客户端提供的额外路径信息。可以使用这些虚拟路径和 PATH_INFO 服务器变量访问脚本。如果该信息来自 URL,在到达 CGI 脚本前就已经由服务器解码了。 |
PATH_TRANSLATED | PATH_INFO 转换后的版本,该变量获取路径并进行必要的由虚拟至物理的映射。 |
QUERY_STRING | 查询 HTTP 请求中问号(?)后的信息。 |
REMOTE_ADDR | 发出请求的远程主机的 IP 地址。 |
REMOTE_HOST | 发出请求的主机名称。如果服务器无此信息,它将设置为空的 MOTE_ADDR 变量。 |
REMOTE_USER | 用户发送的未映射的用户名字符串。该名称是用户实际发送的名称,与服务器上验证过滤器修改过后的名称相对。 |
REQUEST_METHOD | 该方法用于提出请求。相当于用于 HTTP 的 GET、HEAD、POST 等等。 |
SCRIPT_NAME | 执行脚本的虚拟路径。用于自引用的 URL。 |
SERVER_NAME | 出现在自引用 UAL 中的服务器主机名、DNS 化名或 IP 地址。 |
SERVER_PORT | 发送请求的端口号。 |
SERVER_PORT_SECURE | 包含 0 或 1 的字符串。如果安全端口处理了请求,则为 1,否则为 0。 |
SERVER_PROTOCOL | 请求信息协议的名称和修订。格式为 protocol/revision 。 |
SERVER_SOFTWARE | 应答请求并运行网关的服务器软件的名称和版本。格式为 name/version 。 |
URL | 提供 URL 的基本部分。 |
其他几个跟HTTP_前缀有关的变量 | |
ALL_HTTP | 客户端发送的所有带 HTTP_ 前缀的变量。 |
ALL_RAW | 客户端发送的所有HTTP标头,其结果和客户端发送时一样,没有前缀HTTP_ 。 |
HTTP_ | HeaderName 存储在标题文件中的值。未列入该表的标题文件必须以 HTTP_ 作为前缀,以使 ServerVariables 集合检索其值。 |
我们通过.net 的开源代码也可以看到上面的逻辑,这部分的核心代码在 System.Web.HttpRequest 类的 FillInServerVariablesCollection 方法
internal void FillInServerVariablesCollection() {
if (_wr == null)
return;
// Add from hardcoded list
AddServerVariableToCollection("ALL_HTTP", CombineAllHeaders(false));
AddServerVariableToCollection("ALL_RAW", CombineAllHeaders(true));
AddServerVariableToCollection("APPL_MD_PATH");
AddServerVariableToCollection("APPL_PHYSICAL_PATH", _wr.GetAppPathTranslated());
AddServerVariableToCollection("AUTH_TYPE", DynamicServerVariable.AUTH_TYPE);
AddServerVariableToCollection("AUTH_USER", DynamicServerVariable.AUTH_USER);
AddServerVariableToCollection("AUTH_PASSWORD");
AddServerVariableToCollection("LOGON_USER");
AddServerVariableToCollection("REMOTE_USER", DynamicServerVariable.AUTH_USER);
AddServerVariableToCollection("CERT_COOKIE");
AddServerVariableToCollection("CERT_FLAGS");
AddServerVariableToCollection("CERT_ISSUER");
AddServerVariableToCollection("CERT_KEYSIZE");
AddServerVariableToCollection("CERT_SECRETKEYSIZE");
AddServerVariableToCollection("CERT_SERIALNUMBER");
AddServerVariableToCollection("CERT_SERVER_ISSUER");
AddServerVariableToCollection("CERT_SERVER_SUBJECT");
AddServerVariableToCollection("CERT_SUBJECT");
String clString = _wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength);
AddServerVariableToCollection("CONTENT_LENGTH", (clString != null) ? clString : "0");
AddServerVariableToCollection("CONTENT_TYPE", this.ContentType);
AddServerVariableToCollection("GATEWAY_INTERFACE");
AddServerVariableToCollection("HTTPS");
AddServerVariableToCollection("HTTPS_KEYSIZE");
AddServerVariableToCollection("HTTPS_SECRETKEYSIZE");
AddServerVariableToCollection("HTTPS_SERVER_ISSUER");
AddServerVariableToCollection("HTTPS_SERVER_SUBJECT");
AddServerVariableToCollection("INSTANCE_ID");
AddServerVariableToCollection("INSTANCE_META_PATH");
AddServerVariableToCollection("LOCAL_ADDR", _wr.GetLocalAddress());
AddServerVariableToCollection("PATH_INFO", DynamicServerVariable.PATH_INFO);
AddServerVariableToCollection("PATH_TRANSLATED", DynamicServerVariable.PATH_TRANSLATED);
AddServerVariableToCollection("QUERY_STRING", DynamicServerVariable.QUERY_STRING);
AddServerVariableToCollection("REMOTE_ADDR", this.UserHostAddress);
AddServerVariableToCollection("REMOTE_HOST", this.UserHostName);
AddServerVariableToCollection("REMOTE_PORT");
AddServerVariableToCollection("REQUEST_METHOD", this.HttpMethod);
AddServerVariableToCollection("SCRIPT_NAME", DynamicServerVariable.SCRIPT_NAME);
AddServerVariableToCollection("SERVER_NAME", _wr.GetServerName());
AddServerVariableToCollection("SERVER_PORT", _wr.GetLocalPortAsString());
AddServerVariableToCollection("SERVER_PORT_SECURE", _wr.IsSecure() ? "1" : "0");
AddServerVariableToCollection("SERVER_PROTOCOL", _wr.GetHttpVersion());
AddServerVariableToCollection("SERVER_SOFTWARE");
AddServerVariableToCollection("URL", DynamicServerVariable.SCRIPT_NAME);
// Add all headers in HTTP_XXX format
for (int i = 0; i < HttpWorkerRequest.RequestHeaderMaximum; i++) {
String h = _wr.GetKnownRequestHeader(i);
if (!String.IsNullOrEmpty(h))
AddServerVariableToCollection(HttpWorkerRequest.GetServerVariableNameFromKnownRequestHeaderIndex(i), h);
}
String[][] hh = _wr.GetUnknownRequestHeaders();
if (hh != null) {
for (int i = 0; i < hh.Length; i++)
AddServerVariableToCollection(ServerVariableNameFromHeader(hh[i][0]), hh[i][1]);
}
}
小结:
通过上面的代码和说明可以看到:
在客户端发送的HTTP Head 信息中, 是原模原样发送的,并没有增加 HTTP_ 前缀。 服务器段接受到时,也是原模原样的。
按照 W3C 的规范, 除了上述头信息外,其他都需要在服务器端访问时候增加HTTP_ 前缀。 ASP.net 中更极端,除了正常的值获得外。所有值又额外多加了一遍 HTTP_ 前缀。
另外,对于客户段来说,并不是所有 HTTP 头都是可以设置的,下面的是受限制的标头。它们或者直接由 API(如 Content-Type)公开,或者受到系统保护,不能被更改:
Accept
Connection
Content-Length
Content-Type
Date
Expect
Host
If-Modified-Since
Range
Referer
Transfer-Encoding
User-Agent
Proxy-Connection