月度存档: 十二月 2008

Learn HTTP 1.1 Status Code Part.5

Learn HTTP 1.1 Status Code Part.5

by xujiwei(http://www.xujiwei.com/)

前一篇介绍了 4xx 系列状态码 中 406 到 417,这篇接着讲剩下的 5xx 系列。

7. 5xx 系列内部服务器错误

在 服务器处理请求时出问题了,服务器可以发一个 5xx 系列错误码给客户端,表示服务器在处理请求的时候出问题了,问题是出在服务器身上而不是客户端身 上。另外,服务器如果发送了 5xx 系列的状态码,除非客户端是使用的 HEAD 方法,否则服务器还应该在响应中给出错误的描述、原因以及解决方法 等,客户端可以把这些东西给用户看,让用户知道是什么原因导致了请求出错。

不过通常情况下,用户在收到 5xx 系列错误码的同时,是不会 收到导致错误的详细技术信息的,这是为了保护服务端程序安全的需要。服务器一般会返回一个页面描述所出的错误是由什么原因引起的,而不涉及详细技术信息。 例如在 ASP.NET 中,可以在 web.config 中的 customErrors 节配置自定义错误的显示方式,有 On、Off、 RemoteOnly 三种方式,可以根据具体的需要来设置,像 RemoteOnly 就会给本地开发者显示详细的错误信息以及调试信息,而对远程访问 者则会只显示服务器运行时出现错误,没有详细的调试信息。

7.1. 500 Inernal Server Error

500 Internal Server Error 表 示内部服务器错误,这个对于一般用户来说是比较常见的,许多 IIS 服务器都会配置成不发送详细错误信息,而 IIS 的默认设置就是在服务器发生内部 错误时发送 Internal Server Error 这个字符串代替具体的错误信息。

对于 ASP 程序来说,如果是使 用 VBScript 作为脚本语言,那么可以在代码的最前面加一句 On Error Resume Next 来忽略错误继续运行程序,或者加一个错 误处理子程序,或者直接停止脚本的运行,以防止关键信息的泄露。

7.2. 501 Not Implemented

501 未 实现表示服务器对于客户端请求的方法没有实现,从而不能满足客户端的请求。这个错误比较少见,我目前还没有见过这个错误,或者在使用一个开发中 的 Web 服务器时会出现这个错误,例如使用 PUT 方法发送请求但是服务器不支持 PUT 方法,那么服务器就可以发 送 501 Not Implemented 错误码。

7.3. 502 Bad Gateway

当 服务器是作为一个网关或者代理时,在处理客户端请求时从上游服务器收到了一个无效的响应,这时服务器可以返回一个 502 Bad Gateway。

出 现这种情况可能的原因有网关或代理过滤了所请求的网址,或者真正的服务器挂掉了,这些时候代理或网关都可以发送 502 Bad Gateway。

那 么,502 Bad Gateway 是用来表示代理或网关在处理请求时发生了错误,并不一定是原始服务器出现了问题。

7.4. 503 Service Unavailable

503 服 务不可用,表示服务器当前负载过大或者正在维护,这通常表示这是一个临时的情况,服务器会在一定的时间之后恢复正常。如果时间已知,例如服务器在维护,那 么服务器在发送 503 Service Unavailable 的同时,可以在响应头部添加一个 Retry-After 字段表示维护会持续多久, 在指定的时间之后,客户端就可以尝试再次发送请求了。

如果是使用虚拟主机,那么在网站负载过大的时候,一般都会出 现 503 Service Unavailable,因为提供商会限制 CPU 使用率 :)

不过 503 并不一定表示服务器负载过大 或者正在维护,也可能是服务器只是想拒绝处理请求而已。那么,我们也可以在处理 IP 屏蔽之类的情况时直接来一 个 503 Service Unavailable :)

7.5. 504 Gateway Timeout

与 502 Bad Gateway 类 似,这个状态码一般是代理或网关服务器返回的,出现这个状态码意味着代理服务器在处理请求时超过了超时时间仍个没有从原始服务器接收到响应内容,也有可能 是因为在解析原始服务器的域名时超时了。

7.6. 505 HTTP Version Not Supported

客 户端使用 HTTP 版本不被服务器支持,或者服务器拒绝支持客户端所使用的 HTTP 版本,使用向一个只支持 HTTP 1.0 的服务器发送了一个 使用 HTTP 1.1 的请求,那么服务器可以响应 505 HTTP Version Not Supported。在 RFC 指出服务器如果发送 了 505 HTTP Version Not Supported 状态码,那么同时也应该在响应中指出为什么客户端所用的 HTTP 版本不被支持以 及服务器支持哪些协议的哪些版本。

后记

这是本系列的最后一篇了,发现大部分东西都是直接 翻译了 RFC 中的内容,不过也算是把所有的 HTTP 状态码学习了一遍,对于 AJAXRequest 的开发也有了点想法,但是发 现 jQuery 中对 HTTP 状态的处理还算全面,突然觉得 AJAXRequest 有些简陋了。嗯,不过 AJAXRequest 也是我学习 的一个过程,敝帚自珍,哈~

参考资料

  1. HTTP Error 502 – Bad gateway

系 列目录

  1. Learn HTTP 1.1 Status Code Part.1 : Successful 2xx
  2. Learn HTTP 1.1 Status Code Part.2 : Redirection 3xx
  3. Learn HTTP 1.1 Status Code Part.3 : Client Error 400-405
  4. Learn HTTP 1.1 Status Code Part.4 : Client Error 406-417

Learn HTTP 1.1 Status Code Part.4

Learn HTTP 1.1 Status Code Part.4

by xujiwei(http://www.xujiwei.com/)

前一篇介绍了 4xx 系列状态码 中 400 到 405,这篇接着讲剩下的 4xx 系列。

6.7. 406 Not Acceptable

客 户端在收到 406 Not Acceptable 状态码时,一般是因为服务器在处理客户端请求时,找不到对应客户端发送过来的请求头部 的 Accept 字段中列举的响应类型的响应内容,例如使用 Ajax 时,如果通信数据格式选择 json,发送请求时头部 Accept 字段一般 会设置为 application/json,但是如果服务端并不支持 json,那么服务端可以发送一个 406 Not Acceptable,同时 也应该在 Content-Type 字段中指定客户端所请求的资源的格式,这时客户端可以考虑使用另外的格式来接收响应。

不过备注中说 到,如果没有合适的资源来响应客户端的请求,HTTP 1.1 服务器也可以发送一个响应。当然发送 406 Not Accepteble 是一个更好 的选择,这样客户端就能知道什么格式的数据才能是服务器所能接受的。

6.8. 407 Proxy Authentication Required

通 常情况下,这个状态码应该是代理服务器发过来的,表示客户端首先应该进行代理服务器的认证才能继续完成请求,在 IE 里可能会表现为提示用户输入代理服 务器的用户名和密码,如果选择取消则会提示“您必须通过代理的身份验证,然后 Web 服务器才能处理您的请求。”。

6.9. 408 Request Timeout

请 求超时,出现这个状态码时,有可能是服务端的问题,也有可能是客户端的问题(呃,有点废话……)。但是,可能在一些 Web 服务器中,并不会在运行超时 时返回 408 Request Timeout。例如在 ASP 中,如果运行一个超长时间的脚本,IIS 并不会发 送 408 Request Timeout 状态码,而是发送一个 500 Internal Server Error,所以如果在写一个程序时,如 果运行时间已经超过了预期,那么可以自己结束程序运行并向客户端发送一个 408 Request Timeout。

在 HTTP 1.1 状 态码的定义中,如果客户端收到一个 408 Request Timeout 状态码,可以在过一段时间后重新发送这个请求。因此,如果是因为客户端的原 因导致的脚本超时,例如客户端网络速度太慢等,推荐发送一个 408 Request Timeout 状态码,但是如果是由服务器的原因,例如不能处理 过大的文件,则应该直接给出错误,而不是发送一个 408 Request Timeout。

6.10. 409 Conflict

409 Conflict 表 示服务器在处理客户端发送的请求时发生了冲突,和 403 Forbidden、404 Not Found 等一样,服务器应该同时也给出出问题的原因 或解决方法。

很可能发生 409 Conflict 错误的时候是使用 PUT 方法发送请求时,如果所请求的资源已经被第三方修改过,这 时就需要解决两次修改之间的冲突问题。

这个状态码可以与 SVN 中的冲突一起理解,在 SVN 中,如果你修改一个文件的工作副本,在提 交之前又有另外一个人修改并提交了同一个文件的副本,这时就需要解决两个版本之间的冲突,例如合并两个版本之间的不同之处等。

6.11. 410 Gone

如 果客户端请求的资源已经永久删除了,并且不知道有什么其他的资源可以代替它,那么服务器就会发送一个 410 Gone 状态码,指示这个资源已经永久删 除了。如果需要的话,客户端可以在经过用户确认后删除这个资源的链接。如果服务器不能确定客户端所请求的资源是永久的被删除了还是由于某种原因临时不可用 了,那么 404 Not Found 是一个更好的状态码。

一般情况下,410 Gone 可以用于服务器上一些临时的资源,或者不再提 供的某些资源。例如一些不用存档的通知信息等。

与 404 Not Found,这个状态码显示更绝情一些,出 现 404 Not Found 时,服务器的意思是过一段时间之后这个资源有可能还会再可用,但是如果收到了 410 Gone,那么很明显的通知了客 户端“你走吧,这个资源已经不在了,而且也找不到它新的地址了”。那么,如果不是那么确定的时候,还是用 404 Not Found 吧,以后还有“挽 回”的可能。

6.12. 411 Length Required

客户端发送请求时,如 果是使用的 POST 或 PUT 方法,一般都应该加送一个 Content-Length 头,用来指明所发送请求实体的大小,这样服务器在处理请求 时可以提取出整个请求的数据。

如果客户端在发送请求时从服务端收到了一个 411 Length Required 状态码,那么应该在原 来请求的基础上添加一个正确可用的 Content-Length 头部字段再重新发送。

6.13. 412 Precondition Failed

预 处理失败,这通常在客户端发送来的请求中包含了服务端不允许的头部字段或头部字段中的值或其格式不正确,这样可以防止客户端发送一些非法头部信息。

我 对这个状态码的定义并不是很懂,如果理解有错希望指正,原文定义在这里

6.14. 413 Request Entity Too Large

客 户端在收到 413 Request Entity Too Large 状态码时应该意识到它所发送的请求是否过大了。例如在上传文件时,如果选择了一 个过大的文件,那么服务器在没有接收完所有数据时就可能会发送一个 413 Request Entity Too Large 状态码,这时客户端应该 提示用户文件过大并重新选择一个文件等,同时服务器可能会关闭连接以免继续传输请求浪费带宽。

如果出现请求实体过大并不是因为服务器不能处 理过大的文件,而是由于一些临时的原因导致了服务器暂时不能客户端的请求,那么服务器可以在发 送 413 Request Entitiy Too Large 状态码后再头部添加一个 Retry-After 字段,表示客户端可以在此时间之后 重新尝试发送请求。

6.15. 414 Request-URI Too Long

在 HTTP/1.1 Section 3.2.1推荐的 URI 长度应该控制在 255 字节以内,因为一些比较 老的客户端不支持大于 255 字节的 URI。虽然这个限制在现在已经有些过时了,不过浏览器对 URI 的长度也还是有限制的,例如 在 IE 中 URI 的最大长度在 2083 个字节。测试中发现服务器对于 URI 的长度也是有限制的,这也就是 414 Request- URI Too Long 存在的意义了。在服务器觉得客户端所发送的 URI 过长时,就可以返回一个 414 Request- URI Too Long 状态码向客户端说明发生了什么错误。

通常这个情况会发生在客户端使用了 GET 方法去发送本应使 用 POST 方法发送的数据,例如将一个表单使用 GET 方法发送,那么表单中的所有字段会以查询字符器的方式附加到 URI 的最后,这时很有可 能 URI 的长度就会超过了服务器的限制,从而使服务器发送了了 414 Request-URI Too Long 状态码。

还有一种 情况就是用户刻意去构造一个超长的 URI 来攻击服务器了,这个内容不是本篇的范围,就不深入了,我暂时也没能力去讲有关缓冲区溢出之类的内容:)

6.16. 415 Unsupported Media Type

客 户端在发送请求时,一般都需要在头部中添加一下 Content-Type 字段,用于指明所发送请求的内容的类型,例如使用 POST 方法发送表单 时 Content-Type 字段的值就为 application/x-www-form-urlencoded。因此,客户端如果收到 了 415 Unsupported Media Type 状态码,也就意味着它发送的请求的格式不被服务器接受,像在 XML-RPC 的调用过程 中,通信体格式应该为 application/xml 或 text/xml,服务端如果严格检查的话,应该在请求格式不为 application /xml 或 text/xml 时给出一个 415 Unsupported Media Type 的状态码,当然这个检查并不是必须的,XML 也 是文本内容,text/plain 的类型应该也是可接受的。

6.17. 416 Requested Range Not Satisfiable

在 多线程下载中,下载工具是通过在请求头部中添加 Range 字段来指定客户端所需要的资源的内容范围,服务器通过识别这个 Range 字段,定位到资 源的指定位置,并发送指定范围内的内容。如果客户端请求头部中的 Range 字段的起始值超过了它所请求资源的大小并且请求头部没有 If- Range 字段,那么服务器就会返回 416 Request Range Not Satisfiable,这时客户端最好应该删除已经下载的数据并 重新发送一个不带 Range 字段的请求以确定资源的真实大小。

如果是使用字节确定范围的话,那么服务器在返 回 416 Request Range Not Satisfiable 状态码的同时,也应该添加一个 Content-Range 字段,用于指定 客户端所请求的资源的实际大小,这样客户端在收到响应时可以根据请求资源的实际大小重新发送一个请求。

6.18. 417 Expectation Failed

客 户端发送的请求中如果有 Except 字段,但是服务器无法满足的话,那么就可以返回一个 417 Expectation Failed 状态码。

这 个状态码一个常见的用途就是客户端的请求带了一个 Except: 100-continue 字段,但是代理服务器或者 Web 服务器不能处理这个处 理 100 Continue,所以服务器返回 417 Expectation Failded 状态码。

这个状态码 与 100 Continue 以及请求头部 Except 字段之间的关系以及使用可以参考 HTTP/1.1: Connection, Section 8.2.3 Use of the 100 (Continue) Status

后 记

上个星期是学期最后一周,一堆考查课作业要交,晕得一塌糊涂……

未完待续。

参 考资料

1. HTTP/1.1 Protocol Section 3.2.1 General Syntax

2. What is the maximum length of a URL?

3. What is the limit on QueryString / GET / URL parameters?

4. HTTP/1.1: Header Field Definitions

5. HTTP/1.1: Connectinos

系列目录

1. Learn HTTP 1.1 Status Code Part.1 : Successful 2xx

2. Learn HTTP 1.1 Status Code Part.2 : Redirection 3xx

3. Learn HTTP 1.1 Status Code Part.3 : Client Error 400-405

Learn HTTP 1.1 Status Code Part. 3

Learn 1.1 HTTP Status Code Part.3

by xujiwei(http://www.xujiwei.com/)

前一篇介绍了 3xx 系列状态码,这一篇介绍 4xx 客户端错误系列。

6. 客户端错误 4xx 系列状态码

4xx 系列状态码可以算是对用户来说相当熟悉的一类状态码,这个系列的状态码通常都会带一段描述信息来描述服务端在处理请求时出现了什么状况,用户能直观地看到服务端返回的信息,而不像 3xx 系列,浏览器会自动处理那些个状态码,不需要用户的参与。

但是 4xx 系列状态码之间的区别只是它所代表的意义不同,它们的表现形式是可以随心所欲的,例如一些著名站点的 404 页面都是精心设计过的。

6.1. 400 Bad Request

请求格式错误,这可能存在于客户端构造的 HTTP 头不符合要求等,这时服务端会返回一个 400 Bad Request,而客户端在不修改请求数据的情况,不可以再次发送这个请求。

6.2. 401 Unauthorized

未授权错误,用于 HTTP 认证。如果客户端请求的资源需要认证,那么服务端可以响应一个 401 Unauthorized,同时在头部添加一个 WWW-Authenticate 字段表示认证方式,客户端在收到 401 Unauthorized 时,可以提示用户输入用户名和密码,并根据服务端发送过来的认证方式加密认证数据,再重新发送之前的请求。

HTTP 认证方式中认证数据的传送及格式可以参考 RFC 2617 HTTP Authentication: Basic and Digest Access Authentication

<%@LANGUAGE=”JScript” CODEPAGE=”65001″%>
<%
// code from www.xujiwei.com
var auth = Request.ServerVariables(“HTTP_AUTHORIZATION”) + “”;
// 判断客户端输入的用户名及密码是否为 hello 及 world
// aGVsbG86d29ybGQ= 是将用户名密码以冒号连接并使用 BASE64 编码后的字符串
if (auth == ‘Basic aGVsbG86d29ybGQ=’) {
Response.AddHeader(“WWW-Authenticate”, auth);
Response.Write(“Authorized”);
}
else {
Response.Status = “401 Unauthorized”;
Response.AddHeader(‘WWW-Authenticate’, ‘Basic realm=AuthTest’);
Response.Write(“Unauthorized”);
}
%>

6.3. Payment Required

保留的状态码,看字面意思可以在未来用于电子商务之类的网站。

6.4. Forbidden

很直接的,服务端知道客户端想干嘛,但是不想满足它的请求。在服务端XMLHTTP进阶应用-User Agent伪装中有一个简单的例子,使用 ServerXMLHTTP 抓取 Google 新闻的 RSS:

Learn HTTP 1.1 Status Code Part.2

Learn HTTP 1.1 Status Code Part.2

by xujiwei(http://www.xujiwei.com/)

前一篇介绍了 2xx 系列状态码,这一篇介绍 3xx 重定向系列。

5 重定向 3xx 系列状态码

3xx 系列状态码一般是用来作为重定向的,并且在重定向的过程中,一般不需要用户的参与,也就是说,重定向的过程是由浏览器来控制的。但是如果重定向后的请求的方法不是 GET 或 HEAD 的话,还是需要用户参与的,不过也许仅仅是确认一下是否同意发送数据而已:)

另外,开发者要注意的是,RFC2616 Section 10.3 的备注中提到了在前一版本的 HTTP 协议中建议最大重定向次数为 5 次,也就是说,客户端可能只跟踪 5 次重定向,如果超过 5 次重定向,那么可能客户端就会把第 5 次重定向后得到的结果做为最终结果。这时,客户端得到的可能就是一个错误的结果,这就是开发者不愿看到的,那么在开发时,就应该尽量控制重定向次数在 5 次以内。

5.1  300 Multiple Choices

300 Multiple Choices,字面意思是多重选择,表示请求的这个地址具有多个资源可以响应。客户端在遇到 300 Multiple Choices 时,可以自动选择一个最适合的转向地址,或者将所有选项提供给用户由用户来选择一个最适合的转向地址。

除非客户端使用 HEAD 方法来请求,那么如果服务端要返回 300 状态码,那么也应该同时在响应中指出所有可以选择的转向地址列表以便客户端进行选择。但是,目前这个列表的格式并没有一个统一的规范,所以需要客户端与服务端统一规范。

我觉得这个状态码可以用于镜像选择,客户端向服务器请求一个资源,服务器返回一个所有候选资源的列表,客户端从中选取一个速度最快的镜像进行资源下载。

如果没有客户端与服务端之间没有统一规范哪一个资源才是最适合的选择,那么服务端最好在头部中添加 Location 字段指明以服务端来考虑的最适合的转向地址,客户端可以直接使用 Location 字段中的转向地址进行转向而不需要考虑候选资源列表格式是怎么样的或者哪一个选择才是最好的。

经过测试,目前流行的浏览器中,只有 IE 和 Firefox 会对 300 状态码进行识别,Safari、Opera、Chrome 均直接显示响应的内容。由于前面说过的原因,候选列表的格式没有一个统一的规范,所以 IE 和 Firefox 只会根据 Location 字段的值进行转向,如果不指定 Location 字段的值,那么 IE 和 Firefox 也会跟其他浏览器一样只显示响应的内容。

可以使用以下 ASP 代码来测试 300 Multiple Choices:

  • <%@LANGUAGE=”JScript” CODEPAGE=”65001″%>
  • <%
  • // code from www.xujiwei.com
  • Response.Status = “300 Multiple Choices”
  • // 添加一个 Location 字段,IE 和 Firefox 会识别这个字段并重定向
  • Response.AddHeader(“Location”, “test3.asp”);
  • // 输出一个候选资源列表,以 XML 文件的形式
  • // 当然,这个格式只是我测试用的,没有浏览器会认识它
  • Response.ContentType = “application/xml”;
  • Response.Write(“<?xml version=’1.0′ encoding=’utf-8′ ?><locations><location>test3.asp</location><location>test.html</location></locations>”);
  • %>

在 IE 和 Firefox 中浏览包含以上代码的页面时,会自动转向到 test3.asp,而 Safari、Opera、Chrome 则不会。

5.2  301 Moved Permanently

在诸多 SEO 的文章中所说的永久转向就是这位 301 Moved Permanently 了。301 表示当前请求的资源永久地被转移到一个新的 URI 了,除非请求的方法是 HEAD,这个新的 URI 必须在头部的 Location 字段中指出,同时响应内容中最好包含一个指定新地址的超链接,这样,在不支持自动转向的浏览器用户也可以通过点击超链接来重定向到新的 URI。

如果请求时所用的方法不是 GET 或者 HEAD,那么客户端在用户确认前不应自动进行重定向。例如如果浏览器发送了一个 POST 请求,但是收到了 301 Moved Permanently 的响应,那么在重定向到新的 URI 时,可能会使用 GET 方法来请求而不是 POST 方法。

事实上,测试表明,目前的主流浏览器都不会直接重发 POST 请求到 301 重定向后的 URI,而是将请求转换成 GET 方法后再发送,也就是说,在 301 重定向到的服务端程序中,是接收不到最开始客户端 POST 的数据。

通过以下代码可以测试出 POST 请求被转发为 GET 请求:

test.html

  • <!– code from www.xujiwei.com –>
  • <form action=”test.asp” method=”post”>
  • <input type=”text” name=”hello” value=”world” /><input type=”submit” />
  • </form>

test.asp

  • <%@LANGUAGE=”JScript” CODEPAGE=”65001″%>
  • <%
  • // code from www.xujiwei.com
  • // 重定向到 test2.asp
  • Response.Status = “301 Moved Permanently”
  • Response.AddHeader(“Location”, “test2.asp”);
  • %>

test2.asp

  • <%@LANGUAGE=”JScript” CODEPAGE=”65001″%>
  • <%
  • // code from www.xujiwei.com
  • Response.ContentType = “text/html; charset=utf-8”;
  • Response.Write(new Date().toLocaleString() + “<br/>”);
  • // 输出请求方法,预期为 POST,实际为 GET
  • Response.Write(Request.ServerVariables(“HTTP_METHOD”));
  • // 输出表单中字段 hello 的值,预期为 “world”,实际为空字符串
  • Response.Write(Request.Form(“hello”));
  • %>

5.3  302 Found

302 Found 常用于客户端重定向,例如登录完成后重定向到首页等。它表示的是临时重定向,虽然用得多,但是在对于搜索引擎而言却是一个不太友好的东西,所以尽量只在临时转向时才用它。

302 Found 的用法跟 301 Moved Permanently 一样,在 Location 字段中指出要转向的地址,只是所包含的含义不一样而已。

另外,在 RFC 2616 Section 10.3.3 的备注中说到在 RFC 1945 和 RFC 2068 中是不允许客户端改变重定向后的请求方法的,但是目前多数的客户端都是直接重定向然后把方法改为 GET 并舍去 POST 部分的数据,所以在最新的 HTTP 1.1 中添加了 303 和 307 两个状态码来明确是否需要客户端继续以 POST 方式发送请求。

5.4  303 See Other

上面提到了 303 和 307 是用来解决重定向是否要重发 POST 数据不清晰的问题,其中 303 就是用来表示客户端不需要重新发送 POST 数据,可以使用 GET 方法来请求新的地址。

要注意的是,303 响应中 Location 指出的地址并不是原请求地址的完整响应,也就是说,303 可能只是个说明页面,并不一定会对原来请求做出正确的响应

备注中说一些以前的 HTTP 1.1 客户端可能不认识 303,不过现在可以放心的是,主流浏览器都是支持 303 状态码的。

test.asp

  • <%@LANGUAGE=”JScript” CODEPAGE=”65001″%>
  • <%
  • // code from www.xujiwei.com
  • Response.Status = “303 See Other”
  • Response.AddHeader(“Location”, “test2.asp”);
  • %>

反正客户端是会将请求以 GET 方法重新发送的,所以 POST 部分的数据就不用指望了:)

5.5  304 Not Modified

304 Not Modified 是用来表示客户端所请求的资源和上次所请求时没有发生改变,这样服务端就不用重新发送资源的内容,从而减少了网络的负担。

服务端可以由两个头部变量来判断是否发送 304 Not Modified 状态码,一个是 If-Modified-Since,另一个是 If-None-Match,相对应的服务端需要发送的头部变量是 Last-Modified 和 ETag。可以二者选其一,也可以两个都用。PJBlog 就使用了 304 Not Modified 来优化边栏的性能。

  • <%@LANGUAGE=”JScript” CODEPAGE=”65001″%>
  • <%
  • // code from www.xujiwei.com
  • // 从 Session 中获取 ETag 和 Last-Modified 值并发送到客户端
  • var etag = Session(‘etag’) + ‘, lastmod = Session(“lastmod”) + ‘;
  • if(etag == ‘ || etag == ‘undefined’) {
  • Session(‘etag’) = (+new Date()).toString(16);
  • etag = Session(‘etag’) + ‘;
  • }
  • if(lastmod == ‘ || lastmod == ‘undefined’) {
  • Session(‘lastmod’) = new Date().toUTCString();
  • lastmod = Session(‘lastmod’) + ‘;
  • }
  • Response.AddHeader(“ETag”, etag);
  • Response.AddHeader(“Last-Modified”, lastmod);
  • Response.ContentType = “image/jpeg”;
  • // 获取客户端发送过来的 If-None-Match 和 If-Modified-Since 值
  • var etag2 = Request.ServerVariables(“HTTP_IF_NONE_MATCH”) + “”;
  • var lastmod2 = Request.ServerVariables(“HTTP_IF_MODIFIED_SINCE”) + “”;
  • if(etag2 == etag || lastmod == lastmod2) {
  • // 直接响应 304 Not Modified
  • Response.Status = “304 Not Modified”;
  • }
  • else {
  • // 发送完成内容
  • Response.Status = “200 OK”
  • var stream = new ActiveXObject(“ADODB.Stream”);
  • stream.Type = 1;
  • stream.Mode = 3;
  • stream.Open();
  • stream.LoadFromFile(Server.MapPath(‘test.jpg’));
  • Response.BinaryWrite(stream.Read());
  • stream.Close();
  • }
  • %>

5.6  305 Use Proxy

305 Use Proxy 指示客户端需要通过代理来请求当前资源,在头部的 Location 字段中指定代理地址,并且这个状态码只能由原始服务器返回。

但是 RFC 2616 Section 10.3.6 中并没有详细指出 Location 的格式是怎么样的,通过测试发现只有 Safari 会识别 305 Use Proxy,并且直接转向到 Location 中指定的地址。

暂且把它当做一个转向的状态码来用吧,嗯,尽量少用吧,许多浏览器不认识它。

5.7  306 (Unused)

HTTP 1.1 中把它给扔了,所以我们不用管这个状态码了,如果碰到了,直接当错误处理吧。

5.8  307 Temporary Redirect

唔,又是一个不被完全支持的状态码。客户端收到这个状态码时,应该将请求重发到新的地址。而且这个状态码,主要用于 POST 请求,因为如果原始请求是用 GET 方法发送的,那么很可怜的在重定向到新的地址以后,GET 参数会全部舍弃,如果需要在转向后的地址处理 GET 参数,那么自己在服务端程序中加上去吧……

测试中只有 Firefox、Opera 和 IE 会将 POST 请求重定向到新的地址,其中 Firefox 和 Opera 会让用户选择是否重新发送表单到新的地址,而 IE 则是不经用户选择直接把表单重新发送到新的地址,相对而言,Firefox 和 Opera 更安全一些。

如果一定要用这个状态码,为了兼容那些个不认识它的浏览器,服务端需要在响应内容中加个指向新地址的超链接,再加个说明啥的,说明一下怎么用这个新的地址。anyway,少用为上。

后记

3xx 重定向系列用得相当广泛,301、302、304 这三个用得最多。特别需要注意的是 POST 的数据在目前来说基本上是无法直接重定向到一个新的地址的。

ps. 用好 304 很重要:)

系列目录

Learn HTTP 1.1 Status Code Part.1

Comments (0), Views (1091), Pings (0), Leave a response!