规则11——避免重定向
重定向用于将用户从一个URL重新路由到另一个URL。重定向有很多种——301和302是最常用的两种。重定向可能有很多不同的原因,包括网站重新设计、跟踪流量、记录广告点击和建立易于记忆的URL。
重定向的类型
当web服务器向浏览器返回一个重定向时,响应中就会拥有一个范围在3xx的状态码。这表示用户代理必须执行进一步操作才能完成请求。
300 Multiple Choices(基于Content-Type)
301 Moved Permancently
302 Moved Temporarily(亦称Found)
303 See Other(对302的说明)
304 Not Modified
305 Use Proxy
306 (已废弃)
307 Temporary Redirect (对302的说明)
"304 Not Modified"并不真的是重定向——它用来响应条件GET请求,避免下载已经存在于流量器缓存中的数据
301和302是使用得最多的。状态码303和307是在http1.1规范中添加的,用来澄清对302的使用(滥用),但是几乎没有人用303和307,绝大多数网站仍然在沿用302.
下面是一个301响应头的一个示例
浏览器会自动将用户带到Location字段所给出的URL。重定向所必需的所有信息都出现在这个头中了。响应体通常是空的。不管叫什么名字,301和302响应在实际中都不会被缓存,除非有附加的头——如Expires或Cache-Control等——要求它这么做。
还有其他方法可以自动将用户重定向到其他URL。HTML文档的头中包含的meta refresh标签可以在其content属性所指定的秒数之后重定向用户
<meta http-equiv="refresh" content="0; url=http://strbesouders.com/newuri">
javascript也可以用于执行重定向,将document.location设置为期望的url即可。如果你必须进行重定向,最好的技术是使用标准的3xx HTTP状态码,这主要是为了确保后退按钮能够正确工作。
重定向之外的其他选择
缺少结尾的斜线
很多web开发人员没有意识到,在url的结尾必须出现斜线(/)而没出现时,如http://astrology.yahoo.com/as... 包含了一个到http://astrology.yahoo.com/as... 的重定向。当缺少结尾的斜线时发送重定向有着很充分的理由——它允许自动索引(autoindexing,自动转到默认的index.html上)并且能够获得与当前目录相关的url(如logo.gif)。然而,很多流行的web页面并不依赖自动索引,而是依赖特定的url和处理器。另外,url通常也与根目录相关而不是和当前目录相关。
注意当主机名后缺少结尾斜线时不会发生重定向。例如,http://www.yahoo.com 不会产生重定向。然而,你在浏览器中看到的最终的url是包含结尾斜线的——http://www.yahoo.com/ .导致自动产生结尾斜线的原因是,浏览器在运行get请求时必需指定一些路径。如果没有路径,例如http://www.yahoo.com 它就会简单地使用文档根(/)
GET / HTTP 1.1
当缺少结尾斜线时发送重定向是很多web服务器的默认行为,包括Apache. Alias指令是一种简单的方法。另一种选择是使用mod_rewrite模块,但Alias更加简单。(注1)Astrology网站的问题可以通过向Apache配置中添加下列内容来解决——
Alias /astrology /user/local/apache/htdocs/astrology/astrology.html
如果使用Apache2.0中的处理器,一种更为清晰的解决方案是使用DirectorySlash指令。假设有一个名为astrologyhandler的处理器,可以像下面这样使用DirectorySlash
<Localtion /astrology> DirectorySlash Off SetHandler astrologyhandler</Localtion>
这些方法都不能解决查找与当期目录相关的url问题,因此页面中组件的url必须与根目录相关。而且,你还必须知道各模块运行的顺序(尤其是mod_dir和mod_autoindex),因为这样使用DirectorySlash可能会有安全隐患。
总之,如果你的网站包含目录并使用了自动索引,用户就必须忍受一个到达预期页面的重定向。检查一下你的web日志就能看到发出了多少301状态,这能帮助你认识到多么值得去解决缺少结尾斜线的问题。
连接网站
想象一下网站后端被重写的情形。这经常发生,新的实现中的url很可能会有所不同。将用户从旧的url转移到新的url的最简单的方式就是重定向。重定向是使用定义良好的API——url来整合两个代码基础的一种方式。
将旧网站连接到新网站只是重定向这种常见应用中的表现形式之一。其他形式还包括将一个网站的不同部分连接起来,以及基于一些条件(浏览器类型、用户账户类型等)来引导用户。使用重定向来连接两个网站很简单而且只需要很少的额外代码。
其实整合后端还有其他的选择,但比重定向需要更多的开发工作,不过这样不会损害用户体验。
1.Alias、mod_rewrite和DirectorySlash要求除url之外还要提交到一个接口(处理器或文件名),但易于实现。
2.如果两个后端位于同一台服务器,则它们的代码很可能自己就能连接。例如,旧的处理器代码可以通过编程调用新的处理器代码。
3.如果域名变了,可以使用一个CNAME(一条DNS记录,用于创建从一个域名指向另一个域名的别名)让两个主机名指向相同的服务器。如果能做到这一点,这里提到的技术(Alias、mod_rewrite、DirectorySlash和直接连接代码)就是可行的。
跟踪内部流量
重定向经常用于跟踪用户流量的流向。例如,sports链接的url是http://www.yahoo.com/r/26.单...,其Location被设置为http://sports.yahoo.com/。通过分析来自www.yahoo.com的web服务器日志可以得知人们离开Yahoo!的首页后的流量去向。
另一种选择是使用Referer日志来跟踪流量去向。每个http请求都包含一个url,表明从哪个页面发起的请求,也就是引用方(有的时候没有引用页,当用户键入url或使用书签时)。在这里,当用户从Yahoo!主页导航到Sports页时,sports.yahoo.com的访问日志中会包含一个Referer,其值为http://www/yahoo.com/。
跟踪出站流量
出站流量使用referer就不太现实了
Yahoo!search目前将每个搜索结果链接包装到一个重定向中来解决跟踪的问题。搜索结果的url都指向rds.yahoo.com并将最终的目标当作参数包含在该url中。例如,下面是指向wikipedia的“Performance”词条的搜索结果链接
http://rds.yahoo.com/[...]5742/**http%3a/en.wikipedia.org/wiki/Performance
单击这个搜索结果会访问rds.yahoo.com,它将返回一个302响应,其Location被设置为http://en.wikipedia.org/wiki/...**参数就能跟踪用户去了哪里。这个重定向使得获取目标页面变慢了。
除了重定向,还可以选择信标——一个http请求,其url中包含有跟踪信息。跟踪信息可以从信标web服务器的访问日志中提取出来。信标响应通常是一个1px*1px的透明图片;不过204响应更为优秀,因为它更小,从来不会被缓存,而且绝对不会改变浏览器状态。
在Yahoo!search,目标是无论何时用户单击搜索结果链接时都要发送一个信标。这通过为每个连接提供onClick处理器来完成(当启用了javascript时)。onclick处理器将调用一个函数,请求一个图片,并在图片的url中包含要跟踪的信息。
这种情况下,挑战是发送信标和页面自身被卸载之间的竞态情形。图片信标的onload处理器可以用于确保在卸载文档之前信标应传送完毕。
这种方法可能和使用重定向一样慢,另一种方式是使用XMLHttpRequest来发送信标,但在卸载页面之前只需等请求到达readyState 2即可。这比等待重定向的整个http响应要快,但你必须决定是否有必要采取这么复杂的方式。
美化URL
使用重定向的另一种动机是使url更加美观并且易于记忆。如http://www.google.com/tools/f... -> http://www.google.com.
但是,使用alias、mod_rewrite、DirectorySlash和直接链接代码来避免重定向也能达到目的。