<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Time Machine</title>
	<atom:link href="http://rlog.cn/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://rlog.cn</link>
	<description>Rlog.cn</description>
	<lastBuildDate>Mon, 06 Sep 2010 06:11:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>OverFlow &#8211; 一个秘密武器</title>
		<link>http://rlog.cn/?p=623</link>
		<comments>http://rlog.cn/?p=623#comments</comments>
		<pubDate>Sun, 05 Sep 2010 16:05:11 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[工作学习]]></category>
		<category><![CDATA[文摘翻译]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=623</guid>
		<description><![CDATA[如果你已经理解了block formatting contexts那么请继续，否则请先看看这篇文章。 Overflow能够做一些很牛掰的事情，比如: 创建BFC (block formatting contexts via W3c css2.1) 清除浮动 生成块级元素 overyflow属性... ]]></description>
			<content:encoded><![CDATA[<p>如果你已经理解了block formatting contexts那么请继续，否则请先看看<a href="http://rlog.cn/?p=608" target="_blank">这篇文章</a>。</p>
<p>Overflow能够做一些很牛掰的事情，比如:</p>
<ul>
<li>创建BFC (block formatting contexts via <a href="http://www.w3.org/TR/CSS2/visuren.html#block-formatting" target="_blank">W3c css2.1</a>)</li>
<li>清除浮动</li>
</ul>
<h3>生成块级元素</h3>
<p>overyflow属性一旦被指定，那么一个新的BFC就被创建了。这意味着什么呢？它改变了block和浮动元素的交互方式。它不再围绕浮动元素，而是变成一个narrower。</p>
<div style="width: 400px; padding: 10px; background: none repeat scroll 0% 0% #eeeeee;">
<img style="float: left;" src="http://rlog.cn/wp-content/themes/silent/img/rss1.png" alt="" /></p>
<p style="line-height: 1.6em;"><span style="color: #ff6600;">[P没有用overflow]</span>你可以把一个页面想象成大的集装箱，这个集装箱里装的货物就是HTML元素。在现实生活中为了避免 不同人的货物相互混淆，都是把货物打好包装再装入集装箱，这样的话无论你包装里面的货物怎么摆放，都不会影响到其他人的货物。</p>
</div>
<p>&nbsp;</p>
<div style="width: 400px; padding: 10px; background: none repeat scroll 0% 0% #eeeeee;">
<img style="float: left;" src="http://rlog.cn/wp-content/themes/silent/img/rss1.png" alt="" /></p>
<p style="overflow: hidden; line-height: 1.5em;"><span style="color: #ff6600;">[P有用overflow:hidden]</span>你可以把一个页面想象成大的集装箱，这个集装箱里装的货物就是HTML元素。在现实生活中为了避免 不同人的货物相互混淆，都是把货物打好包装再装入集装箱，这样的话无论你包装里面的货物怎么摆放，都不会影响到其他人的货物。</p>
</div>
<p>这不是一个hack，在w3c标准中有明确的说明：</p>
<blockquote><p>The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new <a href="http://www.w3.org/TR/CSS2/visuren.html#block-formatting">block formatting context</a> (such as an element with &#8216;overflow&#8217; other than &#8216;visible&#8217;) must not overlap any floats in the same block formatting context as the element itself.</p></blockquote>
<h3>那么该如何学以致用呢？</h3>
<p>拥有新FC( formatting context)的块级元素会占去一行中所有的剩余空间，只给定位了的浮动元素留下空间。在原文作者的开源项目<a href="http://oocss.org/" target="_blank">OOCSS</a>中，有两种方式去使用FC：</p>
<p><strong>主内容列</strong> -添加FC意味着主内容列将占去除左右列之外的所有空间。这意味着，在一个模板下，只需简单的删除多余的那列，不用做其它任何更改你就可以很轻易的将布局从三列变为两列。CMS开发者会非常喜欢这个特性的。</p>
<p>在Firebug下玩玩<a href="http://oocss.org/template.html" target="_blank">这个模板</a>。</p>
<ol>
<li>试着将“liquid”class增加到“page”元素中。</li>
<li>从HTML中添加或删除一列。</li>
<li>用文档中列出的附加class去扩展一个列对象。</li>
<li>尝试在Firebug中直接改变列的宽度。</li>
</ol>
<p><strong>网格</strong> -任何开发过网格系统的人都知道sub-pixel舍入错误所带来的痛苦。浏览器不知道如何处理33.3像素，所以他们都会做不同的事情。YUI利用“列”之间的“槽”解决了这一差异，但我们也可以在单元内部隐藏这一差异。</p>
<p>一个新的BFC可以用来隐藏网格任何一列最后一个单元的尺寸误差。试试<a href="http://oocss.org/grids_docs.html" target="_blank">这个网格</a>，你会发现当你修改单元的尺寸时，最后的单元会自动伸缩，以适应差异。它没有宽度，而且如果拥有新的BFC，它也不会环绕浮动元素。</p>
<h3>清除浮动</h3>
<p>你肯定听说过清除浮动这码事。人们一直在<a href="http://www.google.com/url?q=http%3A%2F%2Fwww.sitepoint.com%2Fblogs%2F2005%2F02%2F26%2Fsimple-clearing-of-floats%2F&amp;sa=D&amp;sntz=1&amp;usg=AFQjCNEbN2ep_3P4hwtHGrEBAS9m-Zy7eA">探讨通过overflow的属性来清除浮动</a> 。有些人认为它是hack，但仔细阅读规范你会发现，规范作者也没能明确它。因为它的最终解释权归浏览器厂商。</p>
<p>为了计算出什么溢出了容器（这些范围应该被隐藏），他们需要知道块的大小。由于这些块都没有给出明确的高度设置，于是浏览器就使用了从块内容中计算出的高度。欲了解更多关于清除的内容 ，请看我和Eric Meyer在她博客里的<a href="http://meyerweb.com/eric/thoughts/2009/02/16/css3-feedback-layout/#comment-443521" target="_blank">讨论</a>。</p>
<h4>注意事项</h4>
<p>溢出可以太大内容（如巨大的图片，pre区域，或表格之类），我现在尝试overflow: auto，到底使用哪个还需要权衡。</p>
<p>PS: 终于把这篇文章放出来了，其实已经躺在我电脑里好久了，当初答应<a href="http://t.qq.com/ytzong" target="_blank">涛哥</a>翻译的 ，结果拖了这么久实在惭愧。水平所限，文中还有些地方译的很牵强，或者不好理解，希望大家能帮忙指正。原文地址：<a href="http://www.stubbornella.org/content/2009/07/23/overflow-a-secret-benefit/" target="_blank">http://www.stubbornella.org/content/2009/07/23/overflow-a-secret-benefit/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=623</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>革命尚未成功，同志仍须努力</title>
		<link>http://rlog.cn/?p=612</link>
		<comments>http://rlog.cn/?p=612#comments</comments>
		<pubDate>Sat, 24 Jul 2010 06:49:41 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[时光机器]]></category>
		<category><![CDATA[webrebulid]]></category>
		<category><![CDATA[感动]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=612</guid>
		<description><![CDATA[webrebulid已经历了四年风风雨雨，最早得知这个组织的存在是一个叫 wtemplet 的东东，那时心里只是羡慕和崇拜。再看看about里面的那些志愿者，都该是如何的大牛呀。自那时起就默默的给自己立... ]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.webrebuild.org/beijing/banner.jpg" alt="革命尚未成功，同志仍须努力" width="667" height="255" /></p>
<p>webrebulid已经历了四年风风雨雨，最早得知这个组织的存在是一个叫 <a href="http://www.webrebuild.org/wtemplet/" target="_blank">wtemplet</a> 的东东，那时心里只是羡慕和崇拜。再看看about里面的那些志愿者，都该是如何的大牛呀。自那时起就默默的给自己立下了目标&#8230;</p>
<p>时过三年，再去看那些面孔，大部分已是耳熟能详，也曾把酒言欢。此时我才明白，webrebulid 是这样一个无私的领头军，默默的激励着无数的前端爱好者，向自己的目标不断前进。滴水之恩当以涌泉相报，我也希望通过自己微薄的能力去影响更多志同道合者，和大家一起成长。</p>
<p>有幸参与了第二届年会的主办，成功与否要看我们的期望有多高。但不难从与会者的反馈中看出，大家对webrebulid年会是非常肯定的。但成功的欢乐远不及失败的痛苦来的深刻。虚有图表的赞美也不能给进步带来任何帮助，所以我还是想说说问题：</p>
<ol>
<li>关于守时，首先得自我批评，年会前一天约好下午2点去布置会场，我却迟迟未到，害得tension和bonnie两人忙活了一下午。其实这并不是最严重的，由于人手不够，当时确定需要check的一些东西没能及时检查到导致了第二天出现的很多问题，比如签到网络没法使用。由此看来，提前一天对会场环境熟悉，设备调试，是非常重要的。最好有ckeck list, 逐项检查。</li>
<li>关于计划与安排，计划不是万能的，但没有计划是万万不能的。计划需要详尽，但不可能全部覆盖，所以也需要冗余。计划一旦确定，临时的变更也是很危险的。突发事件是不可避免的。大家各司其职，做好自己的份内便是对同伴最好的帮助。</li>
<li>关于路线，路线的问题一开始就考虑到了，可惜没能得到很好的执行。其实网站上画的再详细作用也不是很大，像我这样的路痴其实是很多的。我们可以考虑google纵横或者直接给出地理坐标等“高科技”手段。当然，最现实，最可靠的就是在每个可能的路线上标出方向指示。</li>
<li>关于讨论，在会场就有同学跟我抱怨，讨论时间留的太少了，我们都是抱着问题来的，却没有机会问。这次安排确实有点紧张，上下午共六场，放一天紧张，两天有显松散。所以，webrebulid非常期待您的分享，争取可以做两天，给大家一场前端盛宴。也不枉远方的朋友辛苦跑一趟。</li>
<li>真切的跟yoyo同学说声对不起，签到是我，阿肆和yoyo三人一起负责的，但每每吃饭都没有顾及到她。有机会我跟阿肆一起请你吃饭。</li>
</ol>
<p>幕后许多默默的朋友和台上那些无私的分享者都为这次年会做出了巨大的贡献。你们让我感觉到了无私和凝聚的伟大，谢谢你们。虽然没能听到多少现场的东西， 但有会后的资料， 有图铃兜兜同学的赠书， 有认识这么多朋友，还有你&#8230; 足已!</p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=612</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>白话Block Formatting Context</title>
		<link>http://rlog.cn/?p=608</link>
		<comments>http://rlog.cn/?p=608#comments</comments>
		<pubDate>Sun, 18 Jul 2010 11:11:47 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[工作学习]]></category>
		<category><![CDATA[BFC]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[html]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=608</guid>
		<description><![CDATA[因为在下篇文章中要用到这个概念，刚好找到了这篇不错的文章，就先转过来。 原文链接 一，啥是Block Formatting Context 当涉及到可视化布局的时候，Block Formatting Context提供了一个环境，HTML元素... ]]></description>
			<content:encoded><![CDATA[<p>因为在下篇文章中要用到这个概念，刚好找到了这篇不错的文章，就先转过来。 <a href="http://www.zhoumingzhi.com/2010/06/24/intro-block-formatting-context/">原文链接</a></p>
<h3>一，啥是Block Formatting Context</h3>
<p>当涉及到可视化布局的时候，Block Formatting  Context提供了一个环境，HTML元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。</p>
<p>为了让我们有个感性的认识，举个不太合适的例子。你可以把一个页面想象成大的集装箱，这个集装箱里装的货物就是HTML元素。在现实生活中为了避免 不同人的货物相互混淆，都是把货物打好包装再装入集装箱，这样的话无论你包装里面的货物怎么摆放，都不会影响到其他人的货物。那么这个包装就可以被想象成 Block Formatting Context。</p>
<h3 id="p816-1">二，怎样才能形成Block Formatting Context</h3>
<p>当一个HTML元素满足下面条件的任何一点，都可以产生Block Formatting Context</p>
<ul>
<li>float的值不为none。</li>
<li>overflow的值不为visible。</li>
<li>display的值为table-cell, table-caption, inline-block中的任何一个。</li>
<li>position的值不为relative和static。</li>
</ul>
<h3>三，Block Formatting Context在生产中有什么作用</h3>
<ol>
<li><strong>Block Formatting Context可以阻止边距折叠（margin collapsing）。</strong>我 们知道在一般情况下，两个上下相邻的盒子会折叠它们垂直方向接触到的边距，这种情况只会发生在同一个Block Formatting  Context中。换句话说，在同一个布局环境中（Block Formatting  Context）是边距折叠的必要条件。这也就是为什么浮动的元素和绝对定位元素不会发生边距折叠的原因（当然还有很多种情况也不会折叠）。</li>
<li><strong>Block Formatting Context可以包含内部元素的浮动。</strong>考虑一下下面的例子（<strong>请 用标准浏览器查看</strong>）：
<div class="source" style="font-family: &amp;amp;amp; color: #e6e1dc; background-color: #111111; padding:10px"><span style="color: #cc7833; font-style: italic;">&lt;!DOCTYPE html&gt;</span><br />
<span style="color: #cc7833;">&lt;html&gt;</span><br />
<span style="color: #cc7833;">&lt;head&gt;</span><br />
<span style="color: #cc7833;">&lt;title&gt;</span><span style="color: #e6e1dc;">Demo</span><span style="color: #cc7833;">&lt;/title&gt;</span><br />
<span style="color: #cc7833;">&lt;style </span><span style="color: #ffc66d;">type=</span><span style="color: #a5c261;">&#8220;text/css&#8221;</span><span style="color: #cc7833;">&gt;</span><br />
<span style="color: #cc7833;">html</span><span style="color: #e6e1dc;">,</span> <span style="color: #cc7833;">body</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">margin</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">0</span>;<br />
<span style="color: #cc7833;">padding</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">0</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #ffc66d;">#red</span><span style="color: #e6e1dc;">,</span> <span style="color: #ffc66d;">#orange</span><span style="color: #e6e1dc;">,</span> <span style="color: #ffc66d;">#yellow</span><span style="color: #e6e1dc;">,</span> <span style="color: #ffc66d;">#green</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">width</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">100px</span>;<br />
<span style="color: #cc7833;">height</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">100px</span>;<br />
<span style="color: #cc7833;">float</span><span style="color: #e6e1dc;">:</span> <span style="color: #cc7833;">left</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #ffc66d;">#red</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">background</span><span style="color: #e6e1dc;">:</span> <span style="color: #e6e1dc;">red</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #ffc66d;">#orange</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">background</span><span style="color: #e6e1dc;">:</span> <span style="color: #e6e1dc;">orange</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #ffc66d;">#yellow</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">background</span><span style="color: #e6e1dc;">:</span> <span style="color: #e6e1dc;">yellow</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #ffc66d;">#green</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">background</span><span style="color: #e6e1dc;">:</span> <span style="color: #e6e1dc;">green</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #cc7833;">&lt;/style&gt;</span><br />
<span style="color: #cc7833;">&lt;/head&gt;</span><br />
<span style="color: #cc7833;">&lt;body&gt;</span><br />
<span style="color: #cc7833;">&lt;div</span> <span style="color: #ffc66d;">id=</span><span style="color: #a5c261;">&#8220;c1&#8243;</span><span style="color: #cc7833;">&gt;</span><br />
<span style="color: #cc7833;">&lt;div</span> <span style="color: #ffc66d;">id=</span><span style="color: #a5c261;">&#8220;red&#8221;</span><span style="color: #cc7833;">&gt;&lt;/div&gt;</span><br />
<span style="color: #cc7833;">&lt;div</span> <span style="color: #ffc66d;">id=</span><span style="color: #a5c261;">&#8220;orange&#8221;</span><span style="color: #cc7833;">&gt;&lt;/div&gt;</span><br />
<span style="color: #cc7833;">&lt;/div&gt;</span><br />
<span style="color: #cc7833;">&lt;div</span> <span style="color: #ffc66d;">id=</span><span style="color: #a5c261;">&#8220;c2&#8243;</span><span style="color: #cc7833;">&gt;</span><br />
<span style="color: #cc7833;">&lt;div</span> <span style="color: #ffc66d;">id=</span><span style="color: #a5c261;">&#8220;yellow&#8221;</span><span style="color: #cc7833;">&gt;&lt;/div&gt;</span><br />
<span style="color: #cc7833;">&lt;div</span> <span style="color: #ffc66d;">id=</span><span style="color: #a5c261;">&#8220;green&#8221;</span><span style="color: #cc7833;">&gt;&lt;/div&gt;</span><br />
<span style="color: #cc7833;">&lt;/div&gt;</span><br />
<span style="color: #cc7833;">&lt;/body&gt;</span><br />
<span style="color: #cc7833;">&lt;/html&gt;</span></div>
<p>在上面的代码本意是做一个两行两列的布局，但是由于#red, #orange, #yellow,  #green这四个div同在一个布局环境中，即便通过#c1,  #c2这两个div划分，浮动之后它们还会一个接着一个排列，并不会换行。我们要做的就是把这四个div两两划分到不同的布局环境之中，从而闭合浮动。通 过上面的分析，让#c1<a href="http://www.zhoumingzhi.com/2010/06/24/intro-block-formatting-context/#p816-1">形 成新的Block Formatting Context</a>就可以解决问题。</li>
<li><strong>Block Formatting Context可以阻止元素被浮动覆盖。</strong>请看示例：
<div class="source" style="font-family: &amp;amp;amp; color: #e6e1dc; background-color: #111111; padding:10px"><span style="color: #cc7833; font-style: italic;">&lt;!DOCTYPE html&gt;</span><br />
<span style="color: #cc7833;">&lt;html&gt;</span><br />
<span style="color: #cc7833;">&lt;head&gt;</span><br />
<span style="color: #cc7833;">&lt;title&gt;</span><span style="color: #e6e1dc;">Demo</span><span style="color: #cc7833;">&lt;/title&gt;</span><br />
<span style="color: #cc7833;">&lt;style </span><span style="color: #ffc66d;">type=</span><span style="color: #a5c261;">&#8220;text/css&#8221;</span><span style="color: #cc7833;">&gt;</span><br />
<span style="color: #cc7833;">html</span><span style="color: #e6e1dc;">,</span> <span style="color: #cc7833;">body</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">margin</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">0</span>;<br />
<span style="color: #cc7833;">padding</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">0</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #ffc66d;">#left</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">width</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">100px</span>;<br />
<span style="color: #cc7833;">height</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">100px</span>;<br />
<span style="color: #cc7833;">background</span><span style="color: #e6e1dc;">:</span> <span style="color: #e6e1dc;">red</span>;<br />
<span style="color: #cc7833;">float</span><span style="color: #e6e1dc;">:</span> <span style="color: #cc7833;">left</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #ffc66d;">#right</span> <span style="color: #e6e1dc;">{</span><br />
<span style="color: #cc7833;">height</span><span style="color: #e6e1dc;">:</span> <span style="color: #a5c261;">200px</span>;<br />
<span style="color: #cc7833;">background</span><span style="color: #e6e1dc;">:</span> <span style="color: #e6e1dc;">yellow</span>;<br />
<span style="color: #e6e1dc;">}</span><br />
<span style="color: #cc7833;">&lt;/style&gt;</span><br />
<span style="color: #cc7833;">&lt;/head&gt;</span><br />
<span style="color: #cc7833;">&lt;body&gt;</span><br />
<span style="color: #cc7833;">&lt;div</span> <span style="color: #ffc66d;">id=</span><span style="color: #a5c261;">&#8220;left&#8221;</span><span style="color: #cc7833;">&gt;&lt;/div&gt;</span><br />
<span style="color: #cc7833;">&lt;div</span> <span style="color: #ffc66d;">id=</span><span style="color: #a5c261;">&#8220;right&#8221;</span><span style="color: #cc7833;">&gt;&lt;/div&gt;</span><br />
<span style="color: #cc7833;">&lt;/body&gt;</span><br />
<span style="color: #cc7833;">&lt;/html&gt;</span></div>
<p>在标准浏览器下可以看到，普通的#right元素被浮动的#left元素所覆盖了。要想避免这种情况，有一种方法就是让#right形成新的Block Formatting Context。但是这里一定要注意的是，浮动不会覆盖的只是Block Formatting Context的border-box。换句话说，形成Block Formatting Context元素的margin还是会被浮动所覆盖掉的。</li>
</ol>
<p>这里有更详尽的解释：<a href="http://www.yuiblog.com/blog/2010/05/19/css-101-block-formatting-contexts" target="_blank">http://www.yuiblog.com/blog/2010/05/19/css-101-block-formatting-contexts</a></p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=608</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>HTML5本地存储初探(三)</title>
		<link>http://rlog.cn/?p=590</link>
		<comments>http://rlog.cn/?p=590#comments</comments>
		<pubDate>Sun, 31 Jan 2010 15:40:41 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[工作学习]]></category>
		<category><![CDATA[Client-Side Storage]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[offline]]></category>
		<category><![CDATA[webapp]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=590</guid>
		<description><![CDATA[完成了数据的本地存储，就要将文件存储也搞定。为了实现文件的本地存储，html5搞了一个叫 manifest 的文件，这个文件就是一个缓存清单，把需要缓存在客户端的文件告诉浏览器。manifest是一个... ]]></description>
			<content:encoded><![CDATA[<p>完成了数据的本地存储，就要将文件存储也搞定。为了实现文件的本地存储，html5搞了一个叫 manifest 的文件，这个文件就是一个缓存清单，把需要缓存在客户端的文件告诉浏览器。manifest是一个<span style="color: #ff0000;">mimetype为 text/cache-manifest 的 纯文本文件</span>。注意，这点很重要。</p>
<p>下面是一个manifest文件的例子：</p>
<p><img src="http://img.skitch.com/20100131-mheq73uiue19x7q5g9c52ngtwm.png" alt="manifest" width="356" height="657" /></p>
<p>NETWORK, CACHE, FALLBACK 都是可选的。</p>
<p>manifest文件必须以 CACHE MANIFEST 开头</p>
<p>其后需要下载并缓存的文件使用相对或绝对路径皆可，每个资源一行。</p>
<p>NETWORK段表明一些在线资源所在的域，所有这个域下的资源都不会被缓存，即使客户端处于离线状态，也会尝试去请求基于这些域的资源。</p>
<p>CACHE段还不是很明白</p>
<p>FALLBACK段下面每行都包含两部分内容，用空格分隔。后半部分是当前半部分路径不能访问时的备选路径（很拗），如上图就是，如果demoimages目录不能访问时，尝试访问images目录。</p>
<p>manifest文件介绍就到这里，下面创建我们自己的manifest文件：</p>
<p>我们只需要缓存两个文件即可，nbStyle.css 和 nbScript.js。还有index.html 本身，由于manifest文件会默认缓存引用自己的文件，所以index.html 不能在缓存列表中写出来：</p>
<pre>CACHE MANIFEST
# version: 2010-01-20 22:30

nbStyle.css
nbScript.js</pre>
<p>就是这么简单了，我们将他保存为 notebook.manifest 文件，并和其它文件一起放在根目录。</p>
<p>最后一个问题，如果将notebook.manifest的mimetype标识为 text/cache-manifest 类型呢？我知道有两种方法：</p>
<p>1. 在站点根目录建立 .htaccess 文件，在其中声明.manifest 的mimetype ，这个需要修改下服务器的配置文件，我没有尝试成功。</p>
<p>2. php环境在apache目录寻找一个为 “mime.types” 的配置文件，在其最后添加一行：</p>
<pre>text/cache-manifest            manifest</pre>
<p>然后在index.html文件引用它：<br />
<img src="http://img.skitch.com/20100131-jt9nyer7f41j46mekgn78n3f55.png" alt="引用manifest" width="673" height="98" /><br />
搞定了这些东西，你就可以尝试用webkit访问你的应用，然后离线，再尝试使用它，程序应该也可以照常运行。</p>
<p>至此，html5的离线存储基本介绍完了，下面附上打包的代码，代码本身没有什么难度，只是我写的太烂了:</p>
<p><a href="http://drp.ly/jpQfw">代码下载</a></p>
<p>其实还远没有完，缓存下来的文件如果被更新了怎么办呢？如何通知客户端更新缓存其实也有api，慢慢的再探索吧。非常期待与大家探讨html5相关的问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=590</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>HTML5本地存储初探(二)</title>
		<link>http://rlog.cn/?p=579</link>
		<comments>http://rlog.cn/?p=579#comments</comments>
		<pubDate>Sun, 31 Jan 2010 10:59:26 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[工作学习]]></category>
		<category><![CDATA[Client-Side Storage]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[offline]]></category>
		<category><![CDATA[webapp]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=579</guid>
		<description><![CDATA[完成了UI，我们就需要对数据进行处理了。 在开始“数据”的本地存储之前，我们先来了解一下client-side database storage API: the client-side database storage API allows web applications to store structured data locally ... ]]></description>
			<content:encoded><![CDATA[<p><a href="http://rlog.cn/?p=568">完成了UI</a>，我们就需要对数据进行处理了。</p>
<p>在开始“数据”的本地存储之前，我们先来了解一下client-side database storage API:</p>
<blockquote><p>the client-side database storage API allows web applications to store structured data locally using a medium many web developers are already familiar with – SQL.－－webkit blog</p></blockquote>
<p>目前只有webkit核心的浏览器支持这一特性。你甚至都不能在w3c的html5工作草案中找到 （cs-db）client-side database 的详细描述。</p>
<p>首先我们要尝试建立一个数据库链接：</p>
<pre>try {
	if(!window.openDatabase){  //检测浏览器是否支持cs-db
		alert('not supported cs-db!');
	} else {
		var shortName = 'noteDB';
		var version = '1.0';
		var displayName = 'Note book database';
		var maxSize = 65536;
                //创建一个数据库
		var db = openDatabase(shortName,version,displayName,maxSize);
	}
} catch(e){  //尝试捕获错误
	if (e == 2){
		alert('Invalid database version.');
	} else {
		alert("Unknown error "+e+".");
	}
}</pre>
<p>如果以上代码无误，你就会在safair或者chrome的开发者工具中看到这个数据库：</p>
<p><img src="http://img.skitch.com/20100131-rmki9pjq85xy9nbt436gkdfb7i.png" alt="创建的数据库" width="374" height="180" /></p>
<p>在右侧区域可以直接执行一些sql查询，但是我总是得到 “发生意外错误“0”。” 这样的结果，不知道是不是RP的问题。</p>
<p>接下来就是创建表，以及执行一些sql语句进行增删改查。</p>
<p>js执行sql的基本语法大致是这样的：</p>
<pre>db.transaction(
	function (transaction){
		transaction.executeSql(sqlquery,[],dataHandler, errorHandler);
	}
);</pre>
<p>其中transaction.executeSql中参数依次为：sql查询字符串，传递给sql查询的参数，数据处理句柄，错误处理句柄。其中只有第一项为必选，其余都为可选项。</p>
<p>第二个参数的用法大致是这样的：</p>
<pre>transaction.executeSql("UPDATE people set age=? where name=?;",[ age, name ]);</pre>
<p>查询字符串中的“ ？” 会被后面数组中的变量依次替换。</p>
<p>注意：以上我用了“大致”这个词，因为<span style="text-decoration: line-through;">没有官方的文档</span> （<a href="http://dev.w3.org/html5/webdatabase/" target="_blank">W3C-web database</a>），只是从一些其它文献以及自己判断得来，若有错误还请指正。</p>
<p>下面我们创建一张用来存储note的表：</p>
<pre>db.transaction(
	function (transaction){
		transaction.executeSql(
                'CREATE TABLE IF NOT EXISTS notes (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,titel TEXT, note TEXT NOT NULL, date DATE);',errorHandler);
	}
);</pre>
<p>errorHandler是这样的：</p>
<pre>function errorHandler(transaction, error){
	alert('Error was: '+ error.message +'(Code:'+ error.code +')');

	var fatal_error = true;
	if(fatal_error){
		return true;
	}
	return false;
}</pre>
<p>error.message 是一段错误描述，error.code 是错误代码 (<a href="http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/UsingtheJavascriptDatabase/UsingtheJavascriptDatabase.html#//apple_ref/doc/uid/TP40007256-CH3-SW9" target="_blank">详情</a>)</p>
<p>再看看如果从db中检索出数据并显示到页面上：</p>
<pre>db.transaction(
	function (transaction){
		transaction.executeSql("SELECT * from notes;",[],dataHandler, errorHandler);
	}
);

function dataHandler(transaction, results){
	var string = "";
	for (var i = 0; i" + row['titel'] + "

";
	}
	var listConts = $('listCont');
	listConts.innerHTML = string;
}</pre>
<p>可以看出，基本上和php之类后端语言操作大同小异。<br />
更多代码可查看示例程序，不再一一罗列。</p>
<p>搞定了数据的本地存储之后，接下来就要看看如何将文件储存到本地。</p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=579</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML5本地存储初探(一)</title>
		<link>http://rlog.cn/?p=568</link>
		<comments>http://rlog.cn/?p=568#comments</comments>
		<pubDate>Wed, 27 Jan 2010 09:37:40 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[工作学习]]></category>
		<category><![CDATA[Client-Side Storage]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[offline]]></category>
		<category><![CDATA[webapp]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=568</guid>
		<description><![CDATA[html5带给我们的不仅仅是更多语义丰富的标签，还有更多更牛逼的特性，比如“离线存储”。 对于台式电脑来说，或者它并没有带来什么惊喜，但是对于移动设备来说离线存储简直就是一个神... ]]></description>
			<content:encoded><![CDATA[<p>html5带给我们的不仅仅是更多语义丰富的标签，还有更多更牛逼的特性，比如“离线存储”。 对于台式电脑来说，或者它并没有带来什么惊喜，但是对于移动设备来说离线存储简直就是一个神迹。对于任何拥有支持离线存储浏览器的移动设备，比如iphone，ipod touch，离线存储使得web前端工程师可以很容易的针对它们开发应用程序。</p>
<p>前面吹嘘了一段，不过说实在的，html5本地存储就目前来说还是很受限的。其一，浏览器限制，目前只有 <a href="http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Introduction/Introduction.html">Safari 3.1 and later, and in iPhone OS 2.0 and later</a>. 提供了javascript database 原生支持，不过也有 <a href="http://taffydb.com/index.cfm" target="_blank">Taffy DB</a> 可以曲线救国。(还没有用过，不敢妄下结论。)。 其二，服务器端需要修改配置，旦如果是自己的服务器就很简单了。</p>
<p>下面就以一个简单的offline web app－note book 为例，记录一下为iphone/ipod touch开发web app的过程。不是经验，只是初探。</p>
<ol>
<li><a href="http://rlog.cn/?p=568">建立适合 iphone/ipod touch 的UI</a></li>
<li><a href="http://rlog.cn/?p=579">数据的本地存储</a></li>
<li><a href="http://rlog.cn/?p=590">文件的本地存储</a></li>
<li><span style="text-decoration: line-through;">完善这个app</span> (不打算完善它了，有时间做一个实用的app专门介绍 iphone web app 的开发吧)</li>
</ol>
<p>首先，适合iphone/ipod touch 的UI 它并不是本文的重点，有兴趣的同学可以<a href="http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariWebContent/Introduction/Introduction.html" target="_blank">移步这里</a> 。这里只强调一点：你默认做的页面，放到iphone看会变的很窄，字很小。这是因为iphone用它320px宽的屏幕显示了一个默认980px宽的页面，你的内容被按比例缩小了。要解决这个问题很简单，只要在html的head区域加一个meta标记，具体语法请看<a href="http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html#//apple_ref/html/const/viewport" target="_blank">这里</a> 。 也就是这样：</p>
<p><img src="http://img.skitch.com/20100127-nt3aii2bftxqusxnd37rixkyjy.png" alt="viewport" width="637" height="112" /></p>
<p>这个问题解决之后我们就可以肆意的使用html5和css3来打造界面了，（针对设备开发可以不考虑兼容性，真是畅快淋漓呀。）</p>
<p>我大概做了个丑陋的界面：</p>
<p><img src="http://img.skitch.com/20100127-g97wp4y1e4kibb28uau2cswtea.png" alt="app UI" width="319" height="402" /></p>
<p><a href="http://fayaa.com/code/view/9035/full/" target="_blank">html代码</a>， <a href="http://fayaa.com/code/view/9036/full/" target="_blank">CSS代码</a> (其实你可以不用看，最后有打包的代码)</p>
<p>这篇先到这里，太长了你看着累我写着也累，咱慢慢来。:)</p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=568</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Asaph－私人的网络菜篮子</title>
		<link>http://rlog.cn/?p=565</link>
		<comments>http://rlog.cn/?p=565#comments</comments>
		<pubDate>Mon, 04 Jan 2010 14:44:24 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[懒得分类]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=565</guid>
		<description><![CDATA[首先感谢何必呢共享他的delicious给我，里面确实有不少好东西，Asaph就是其中一个。说白了他就是一个网络资源收集器。可以把喜欢的图片，文字，网站以“碎片”的形式储存到一个个人微博，... ]]></description>
			<content:encoded><![CDATA[<p>首先感谢<a href="http://www.hebine.net/">何必呢</a>共享他的delicious给我，里面确实有不少好东西，Asaph就是其中一个。说白了他就是一个网络资源收集器。可以把喜欢的图片，文字，网站以“碎片”的形式储存到一个个人微博，作为自己的资源库备用。<br />
Asaph的官方网站在这里：<a href="http://www.phoboslab.org/projects/asaph">http://www.phoboslab.org/projects/asaph</a> 。 这个是作者的演示站点：<a href="http://www.phoboslab.org/projects/asaph">http://www.phoboslab.org/projects/asaph</a>。<br />
使用很简单：</p>
<ul>
<li>下载Asaph程序</li>
<li>修改lib/asaph_config.class.php 里面的 $domain，$absolutePath 以及 $db 变量。</li>
<li>将这个目录上传至自己的php空间，并建立数据库。(需要将data目录权限改为777)</li>
<li>访问admin/install.php进行安装并设置用户名密码。</li>
<li>完成后访问 admin/ 目录，在界面左下角有一个“ASAPH”的Bookmarklet，将其拖放至你的收藏栏。</li>
<li>All Done 以后见到想收藏的内容就点收藏栏上的ASAPH书签，然后点选你感兴趣的内容部分就发布到你自己的ASAPH网站了。</li>
</ul>
<p>ASAPH的网站有段视频，看看就明白了。<br />
Bookmarklet是个很不错的工具，完全可以用它来做一些浏览器小插件。</p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=565</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>2010, Do More!</title>
		<link>http://rlog.cn/?p=541</link>
		<comments>http://rlog.cn/?p=541#comments</comments>
		<pubDate>Fri, 01 Jan 2010 13:35:23 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[时光机器]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=541</guid>
		<description><![CDATA[.cubeIE{height:470px;}.cube {position: absolute;}.cube .face {position: absolute; width: 200px;height: 200px;background:red;}.cube .top {-moz-transform: rotate(-45deg) skew(15deg, 15deg);-webkit-transform: rotate(-45deg) skew(15deg, 15deg);background:#ee... ]]></description>
			<content:encoded><![CDATA[<p><!--[if IE]><br />
<style type="text/css">.cube{display:none;}.cubeIE{background:url(http://img.skitch.com/20100101-e4e7946bbwc3tybdmcqc9uix5u.png) no-repeat}</style>
<p><![endif]--><br />
<style type="text/css">.cubeIE{height:470px;}.cube {position: absolute;}.cube .face {position: absolute; width: 200px;height: 200px;background:red;}.cube .top {-moz-transform: rotate(-45deg) skew(15deg, 15deg);-webkit-transform: rotate(-45deg) skew(15deg, 15deg);background:#eee;left:90px;top:43px;}.cube .left {-moz-transform: rotate(15deg) skew(15deg, 15deg);-webkit-transform: rotate(15deg) skew(15deg, 15deg);background:#bbb;top:200px;}.cube .left p {color: #666;background-color: #ccc;}.cube .right {-moz-transform: rotate(-15deg) skew(-15deg, -15deg);-webkit-transform: rotate(-15deg) skew(-15deg, -15deg);background:#ccc;top:200px;left:180px;}.cube .right p {color: #999;background-color: #ddd;}.cube .right ul {margin-left: 25px;line-height: 1.5;color: #666;}.cube a{text-decoration: none;color: #666;font-size: 24px;display: block;text-align: center;margin-top: 10px;}.cube a:hover{color: #222;}.cube dl{color: #333;}</style>
<div class="cube">
<div class="face top"></div>
<div class="face left">
	    	<a href="http://rlog.cn">&nbsp;</a></p>
<p>201020102010201020102010</p>
</p></div>
<div class="face right">
	    	<a href="http://rlog.cn">RLOG</a></p>
<p>2010201020102010201020</p>
<ul>
<li>Do More!</li>
<li>Do Better!</li>
<li>Think Deeper!</li>
<li>Think Farther!</li>
</dl></div>
</p></div>
<p class="cubeIE">&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=541</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>第三期web标准化交流会杂感</title>
		<link>http://rlog.cn/?p=536</link>
		<comments>http://rlog.cn/?p=536#comments</comments>
		<pubDate>Sat, 26 Dec 2009 16:10:43 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[时光机器]]></category>
		<category><![CDATA[w3cteach]]></category>
		<category><![CDATA[微格式]]></category>
		<category><![CDATA[聚会]]></category>
		<category><![CDATA[语义]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=536</guid>
		<description><![CDATA[会上气氛相当不错，但唯一不足我们后来FB时提到，同学们做自我介绍时须加上“单身否”一项。 关于DTD我有一疑问没来得及问，为什么html5取消了dtd声明？也就是说w3c觉得dtd并不是那么重要的... ]]></description>
			<content:encoded><![CDATA[<p>会上气氛相当不错，但唯一不足我们后来FB时提到，同学们做自我介绍时须加上“单身否”一项。</p>
<p>关于DTD我有一疑问没来得及问，为什么html5取消了dtd声明？也就是说w3c觉得dtd并不是那么重要的东西？</p>
<p>关于验证，我很同意<a href="http://www.greengnn.org/index.php/2009/12/26/17.html" target="_blank">greengnn</a>，因为验证可以提供一条基线，使大家有最起码的标准可依。关于语义化其实有很多同学还是存疑的，它在目前来看存在的意义到底是什么？我觉得还是会后winter的解释很有说服力：我们先撇开对机器友好不谈。对于开发者来说任何编程语言都需要语义的，如果你一个页面全用div，那么后期维护，或者别人接手你的项目时，有什么样的感觉呢？很难找到哪里是哪里，就好比其它开发语言中使用无语义的变量一样让人恼火。试试读一段变量混淆过的js，你就知道了。读一段无语义的html就好像读一篇没有标点的文章，多郁闷。</p>
<p>微格式，可能大家觉得平时用到的比较少，就没有太重视，我觉得语义化标签与微格式是相互补充的。或者可以说，微格式是对html语义的一个扩充。微格式可用使得你的html代码可以被更多设备识别并使用。《精通HTML》第5，6章有详细的描述，推荐大家读读。其实如果用同学用过IE8的网页剪辑功能，其实那段代码就是一种可被IE8识别的微格式子类，还有qq空间首页上也使用了微格式，你可用尝试使用ff的插件<a href="https://addons.mozilla.org/zh-CN/firefox/addon/4106" target="_blank">Operator</a> 将这些vCard微格式导出为hCard，供outlook之类的通讯软件使用。tommy有<a href="http://tommyfan.com/blog/skill/add_phone_from_hcard/" target="_blank">两篇文章</a>可看看。<a href="http://www.aoao.org.cn/?s=%E5%BE%AE%E6%A0%BC%E5%BC%8F" target="_blank">aoao的blog</a>也有不少微格式相关的文章。</p>
<p>最后，一点建议：可能是讨论的点有点多，所以很难深入进去讨论。希望下次能围绕一两个，或者两三个问题深入的探讨一下。</p>
<p>很遗憾没有时间进行html5和css3的讨论，希望下次有机会和大家一起再聚。</p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=536</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>HTTP Headers 入门</title>
		<link>http://rlog.cn/?p=521</link>
		<comments>http://rlog.cn/?p=521#comments</comments>
		<pubDate>Thu, 03 Dec 2009 14:36:59 +0000</pubDate>
		<dc:creator>Robin</dc:creator>
				<category><![CDATA[文摘翻译]]></category>
		<category><![CDATA[读书笔记]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://rlog.cn/?p=521</guid>
		<description><![CDATA[本文系统的对HTTP Headers进行了简明易懂的阐... ]]></description>
			<content:encoded><![CDATA[<p>非常感谢 <a href="http://www.99css.com/" target="_blank">@ytzong</a> 同学在<a href="https://www.twitter.com/ytzong/status/6266688471" target="_blank">twitter上推荐</a>这篇文章，<a href="http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/" target="_blank">原文在此</a>。</p>
<p>本文系统的对HTTP Headers进行了简明易懂的阐述，我仅稍作笔记。</p>
<h3>什么是HTTP Headers</h3>
<p>HTTP是“Hypertext Transfer Protocol”的所写，整个万维网都在使用这种协议，几乎你在浏览器里看到的大部分内容都是通过http协议来传输的，比如这篇文章。</p>
<p>HTTP Headers是HTTP请求和相应的核心，它承载了关于客户端浏览器，请求页面，服务器等相关的信息。</p>
<p><img class="alignnone" title="http_diagram" src="http://nettuts.s3.amazonaws.com/511_http/http_diagram.png" alt="" width="537" height="429" /><br />
<span id="more-521"></span></p>
<h3>示例</h3>
<p>当你在浏览器地址栏里键入一个url，你的浏览器将会类似如下的http请求：<br />
<code>GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1<br />
Host: net.tutsplus.com<br />
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)<br />
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br />
Accept-Language: en-us,en;q=0.5<br />
Accept-Encoding: gzip,deflate<br />
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7<br />
Keep-Alive: 300<br />
Connection: keep-alive<br />
Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120<br />
Pragma: no-cache<br />
Cache-Control: no-cache<br />
</code><br />
第一行被称为“Request Line” 它描述的是这个请求的基本信息，剩下的就是HTTP headers了。</p>
<p>请求完成之后，你的浏览器可能会收到如下的HTTP响应：</p>
<p><code>HTTP/1.x 200 OK<br />
Transfer-Encoding: chunked<br />
Date: Sat, 28 Nov 2009 04:36:25 GMT<br />
Server: LiteSpeed<br />
Connection: close<br />
X-Powered-By: W3 Total Cache/0.8<br />
Pragma: public<br />
Expires: Sat, 28 Nov 2009 05:36:25 GMT<br />
Etag: "pub1259380237;gz"<br />
Cache-Control: max-age=3600, public<br />
Content-Type: text/html; charset=UTF-8<br />
Last-Modified: Sat, 28 Nov 2009 03:50:37 GMT<br />
X-Pingback: http://net.tutsplus.com/xmlrpc.php<br />
Content-Encoding: gzip<br />
Vary: Accept-Encoding, Cookie, User-Agent<br />
&lt;!-- ... rest of the html ... --&gt;</code></p>
<p>第一行呢被称为“Status Line”，它之后就是http headers，空行完了就开始输出内容了（在这个案例中是一些html输出）。</p>
<p>但你查看页面源代码却不能看到HTTP headers，虽然它们同你能看到的东西一起被传送至浏览器了。</p>
<p>这个HTTP请求也发出了一些其它资源的接收请求，例如图片，css文件，js文件等等。</p>
<p>下面我们来看看细节。</p>
<h3>怎样才能看到HTTP Headers</h3>
<p>下面这些FireFox扩展能够帮助你分析HTTP headers：</p>
<p>1. <a href="http://getfirebug.com/" target="_blank">firebug</a></p>
<p><img class="alignnone" title="firebu" src="http://nettuts.s3.amazonaws.com/511_http/firebug.png" alt="" width="549" height="650" /></p>
<p>2.<a href="https://addons.mozilla.org/en-US/firefox/addon/3829">Live HTTP Headers</a></p>
<p><img class="alignnone" title="live_http" src="http://nettuts.s3.amazonaws.com/511_http/live_http.png" alt="" width="578" height="702" /></p>
<p>3. 在PHP中：</p>
<ul>
<li><a href="http://php.net/manual/en/function.getallheaders.php">getallheaders()</a> 用来获取请求头部. 你也可以使用 $_SERVER 数组.</li>
<li><a href="http://www.php.net/manual/en/function.headers-list.php">headers_list()</a> 用来获取响应头部.</li>
</ul>
<p>文章下面将会看到一些使用php示范的例子。</p>
<h3>HTTP Request 的结构</h3>
<p><img class="alignnone" title="request_header" src="http://nettuts.s3.amazonaws.com/511_http/request_header.png" alt="" width="590" height="247" /></p>
<p>被称作“first line”的第一行包含三个部分：</p>
<ul>
<li>&#8220;method&#8221; 表明这是何种类型的请求. 最常见的请求类型有 GET, POST 和 HEAD.</li>
<li>&#8220;path&#8221; 体现的是主机之后的路径. 例如，当你请求 &#8220;http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/&#8221;时 , path 就会是 &#8220;/tutorials/other/top-20-mysql-best-practices/&#8221;.</li>
<li>&#8220;protocol&#8221; 包含有 &#8220;HTTP&#8221; 和版本号, 现代浏览器都会使用1.1.</li>
</ul>
<p>剩下的部分每行都是一个“Name：Value”对。它们包含了各式各样关于请求和你浏览器的信息。例如”User-Agent“就表明了你浏览器版本和你所用的操作系统。”Accept-Encoding“会告诉服务器你的浏览可以接受类似gzip的压缩输出。</p>
<p>这些headers大部分都是可选的。HTTP 请求甚至可以被精简成这样子：</p>
<p><code>GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1<br />
Host: net.tutsplus.com</code></p>
<p>并且你仍旧可以从服务器收到有效的响应。</p>
<h3><span>请求类型</span></h3>
<p>三种最常见的请求类型是：GET，POST 和 HEAD ，从html的编写过程中你可能已经熟悉了前两种。</p>
<h3><span>GET：获取一个文档</span></h3>
<p>大部分被传输到浏览器的html，images，js，css, &#8230; 都是通过GET方法发出请求的。它是获取数据的主要方法。</p>
<p>例如，要获取Nettuts+ 的文章，http request的第一行通常看起来是这样的：</p>
<p><code>GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1</code></p>
<p>一旦html加载完成，浏览器将会发送GET 请求去获取图片，就像下面这样：</p>
<p><code>GET /wp-content/themes/tuts_theme/images/header_bg_tall.png HTTP/1.1</code></p>
<p>表单也可以通过GET方法发送，下面是个例子：</p>
<p><code>&lt;form action="foo.php" method="GET"&gt;<br />
First Name: &lt;input name="first_name" type="text" /&gt;<br />
Last Name: &lt;input name="last_name" type="text" /&gt;<br />
&lt;input name="action" type="submit" value="Submit" /&gt;<br />
&lt;/form&gt;</code></p>
<p>当这个表单被提交时，HTTP request 就会像这样：</p>
<p><code>GET /foo.php?first_name=John&amp;last_name=Doe&amp;action=Submit HTTP/1.1<br />
...</code></p>
<p>你可以将表单输入通过附加进查询字符串的方式发送至服务器。</p>
<h3>POST：发送数据至服务器</h3>
<p>尽管你可以通过GET方法将数据附加到url中传送给服务器，但在很多情况下使用POST发送数据给服务器更加合适。通过GET发送大量数据是不现实的，它有一定的局限性。</p>
<p>用POST请求来发送表单数据是普遍的做法。我们来吧上面的例子改造成使用POST方式：</p>
<p><code>&lt;form action="foo.php" method="POST"&gt;<br />
First Name: &lt;input name="first_name" type="text" /&gt;<br />
Last Name: &lt;input name="last_name" type="text" /&gt;<br />
&lt;input name="action" type="submit" value="Submit" /&gt;<br />
&lt;/form&gt;</code></p>
<p>提交这个表单会创建一个如下的HTTP 请求：</p>
<p><code>POST /foo.php HTTP/1.1<br />
Host: localhost<br />
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)<br />
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br />
Accept-Language: en-us,en;q=0.5<br />
Accept-Encoding: gzip,deflate<br />
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7<br />
Keep-Alive: 300<br />
Connection: keep-alive<br />
Referer: http://localhost/test.php<br />
Content-Type: application/x-www-form-urlencoded<br />
Content-Length: 43<br />
first_name=John&amp;last_name=Doe&amp;action=Submit</code></p>
<p>这里有三个需要注意的地方：</p>
<ul>
<li>第一行的路径已经变为简单的 /foo.php , 已经没了查询字符串。</li>
<li>新增了 Content-Type 和 Content-Lenght 头部，它提供了发送信息的相关信息.</li>
<li>所有数据都在headers之后，以查询字符串的形式被发送.</li>
</ul>
<p>POST方式的请求也可用在AJAX，应用程序，cURL &#8230; 之上。并且所有的文件上传表单都被要求使用POST方式。</p>
<h3>HEAD：接收头部信息</h3>
<p>HEAD和GET很相似，只不过HEAD不接受HTTP响应的内容部分。当你发送了一个HEAD请求，那就意味着你只对HTTP头部感兴趣，而不是文档本身。</p>
<p>这个方法可以让浏览器判断页面是否被修改过，从而控制缓存。也可判断所请求的文档是否存在。</p>
<p>例如，假如你的网站上有很多链接，那么你就可以简单的给他们分别发送HEAD请求来判断是否存在死链，这比使用GET要快很多。</p>
<h3>http响应结构</h3>
<p>当浏览器发送了HTTP请求之后，服务器就会通过一个HTTP response来响应这个请求。如果不关心内容，那么这个请求看起来会是这样的：</p>
<p><img class="alignnone" title="response_header" src="http://nettuts.s3.amazonaws.com/511_http/response_header.png" alt="" width="424" height="249" /></p>
<p>第一个有价值的信息就是协议。目前服务器都会使用 HTTP/1.x 或者 HTTP/1.1。</p>
<p>接下来一个简短的信息代表状态。代码200意味着我们的请求已经发送成功了，服务器将会返回给我们所请求的文档，在头部信息之后。</p>
<p>我们都见过“404”页面。当我向服务器请求一个不存在的路径时，服务器就用用404来代替200响应我们。</p>
<p>余下的响应内容和HTTP请求相似。这些内容是关于服务器软件的，页面/文件何时被修改过，mime type 等等&#8230;</p>
<p>同样，这些头部信息也是可选的。</p>
<h2>HTTP状态码</h2>
<ul>
<li>200 用来表示请求成功.</li>
<li>300 来表示重定向.</li>
<li>400 用来表示请求出现问题.</li>
<li>500 用来表示服务器出现问题.</li>
</ul>
<p><strong>200 成功 （OK）</strong></p>
<p>前文已经提到，200是用来表示请求成功的。</p>
<p><strong>206 部分内容 （Partial Content）</strong></p>
<p>如果一个应用只请求某范围之内的文件，那么就会返回206.</p>
<p>这通常被用来进行下载管理，断点续传或者文件分块下载。</p>
<p><strong>404 没有找到 （Not Found）</strong></p>
<p><img src="http://nettuts.s3.amazonaws.com/511_http/404.png" alt="404" width="547" height="272" /></p>
<p>很容易理解</p>
<p><strong>401 未经授权 （Unauthorized）</strong></p>
<p>受密码保护的页面会返回这个状态。如果你没有输入正确的密码，那么你就会在浏览器中看到如下的信息：</p>
<p><img src="http://nettuts.s3.amazonaws.com/511_http/401.png" alt="401" width="542" height="280" /></p>
<p>注意这只是受密码保护页面，请求输入密码的弹出框是下面这个样子的：</p>
<p><img src="http://nettuts.s3.amazonaws.com/511_http/401_prompt.png" alt="401_prompt" width="548" height="348" /></p>
<p><strong>403 被禁止（Forbidden）</strong></p>
<p>如果你没有权限访问某个页面，那么就会返回403状态。这种情况通常会发生在你试图打开一个没有index页面的文件夹。如果服务器设置不允许查看目录内容，那么你就会看到403错误。</p>
<p>其它一些一些方式也会发送权限限制，例如你可以通过IP地址进行阻止，这需要一些htaccess的协助。</p>
<p><code>order allow,deny<br />
deny from 192.168.44.201<br />
deny from 224.39.163.12<br />
deny from 172.16.7.92<br />
allow from all</code></p>
<p><strong>302（或307）临时移动（Moved Temporarily） 和 301 永久移动（Moved Permanently）</strong></p>
<p>这两个状态会出现在浏览器重定向时。例如，你使用了类似 bit.ly 的网址缩短服务。这也是它们如何获知谁点击了他们链接的方法。</p>
<p>302和301对于浏览器来说是非常相似的，但对于搜索引擎爬虫就有一些差别。打个比方，如果你的网站正在维护，那么你就会将客户端浏览器用302重定向到另外一个地址。搜索引擎爬虫就会在将来重新索引你的页面。但是如果你使用了301重定向，这就等于你告诉了搜索引擎爬虫：你的网站已经永久的移动到了新的地址。</p>
<p><strong>500 服务器错误（Internal Server Error）</strong></p>
<p><img class="alignnone" src="http://nettuts.s3.amazonaws.com/511_http/500.png" alt="" /></p>
<p>这个代码通常会在页面脚本崩溃时出现。大部分CGI脚本都不会像PHP那样输出错误信息给浏览器。如果出现了致命的错误，它们只会发送一个500的状态码。这时需要查看服务器错误日志来排错。</p>
<p><strong>完整的列表</strong></p>
<p>你可以<a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes" target="_blank">在这里</a>找到完整的HTTP 状态码说明。</p>
<h2>HTTP Headers 中的 HTTP请求</h2>
<p>现在我们来看一些在HTTP headers中常见的HTTP请求信息。</p>
<p>所有这些头部信息都可以在PHP的$_SERVER数组中找到。你也可以用<a href="http://php.net/manual/en/function.getallheaders.php">getallheaders()</a> 函数一次性获取所有的头部信息。</p>
<h3>Host</h3>
<p>一个HTTP请求会发送至一个特定的IP地址，但是大部分服务器都有在同一IP地址下托管多个网站的能力，那么服务器必须知道浏览器请求的是哪个域名下的资源。</p>
<p><code>Host: rlog.cn</code></p>
<p>这只是基本的主机名，包含域名和子级域名。</p>
<p>在PHP中，可以通过$_SERVER['HTTP_HOST'] 或 $_SERVER['SERVER_NAME']来查看。</p>
<h3>User-Agent</h3>
<p><code>User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)</code></p>
<p>这个头部可以携带如下几条信息：</p>
<ul>
<li>浏览器名和版本号.</li>
<li>操作系统名和版本号.</li>
<li>默认语言.</li>
</ul>
<p>这就是某些网站用来收集访客信息的一般手段。例如，你可以判断访客是否在使用手机访问你的网站，然后决定是否将他们引导至一个在低分辨率下表现良好的移动网站。</p>
<p>在PHP中，可以通过 $_SERVER['HTTP_USER_AGENT'] 来获取User-Agent</p>
<p><code>if ( strstr($_SERVER['HTTP_USER_AGENT'],'MSIE 6') ) {<br />
echo "Please stop using IE6!";<br />
}</code></p>
<h3>Accept-Language</h3>
<p><code>Accept-Language: en-us,en;q=0.5</code></p>
<p>这个信息可以说明用户的默认语言设置。如果网站有不同的语言版本，那么就可以通过这个信息来重定向用户的浏览器。</p>
<p>它可以通过逗号分割来携带多国语言。第一个会是首选的语言，其它语言会携带一个“q”值，来表示用户对该语言的喜好程度（0~1）。</p>
<p>在PHP中用 $_SERVER["HTTP_ACCEPT_LANGUAGE"] 来获取这一信息。</p>
<p><code>if (substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2) == 'fr') {<br />
header('Location: http://french.mydomain.com');<br />
}</code></p>
<h3>Accept-Encoding</h3>
<p><code>Accept-Encoding: gzip,deflate</code></p>
<p>大部分的现代浏览器都支持gzip压缩，并会把这一信息报告给服务器。这时服务器就会压缩过的HTML发送给浏览器。这可以减少近80%的文件大小，以节省下载时间和带宽。</p>
<p>在PHP中可以使用 $_SERVER["HTTP_ACCEPT_ENCODING"] 获取该信息。 然后调用<a href="http://www.php.net/manual/en/function.ob-gzhandler.php">ob_gzhandler()</a>方法时会自动检测该值，所以你无需手动检测。</p>
<p><code>// enables output buffering<br />
// and all output is compressed if the browser supports it<br />
ob_start('ob_gzhandler');</code></p>
<h3>If-Modified-Since</h3>
<p>如果一个页面已经在你的浏览器中被缓存，那么你下次浏览时浏览器将会检测文档是否被修改过，那么它就会发送这样的头部：</p>
<p><code>If-Modified-Since: Sat, 28 Nov 2009 06:38:19 GMT</code></p>
<p>如果自从这个时间以来未被修改过，那么服务器将会返回“304 Not Modified”，而且不会再返回内容。浏览器将自动去缓存中读取内容</p>
<p>在PHP中，可以用$_SERVER['HTTP_IF_MODIFIED_SINCE'] 来检测。</p>
<p><code>// assume $last_modify_time was the last the output was updated<br />
// did the browser send If-Modified-Since header?<br />
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {<br />
// if the browser cache matches the modify time<br />
if ($last_modify_time == strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {<br />
// send a 304 header, and no content<br />
header("HTTP/1.1 304 Not Modified");<br />
exit;<br />
}<br />
}</code></p>
<p>还有一个叫Etag的HTTP头信息，它被用来确定缓存的信息是否正确，稍后我们将会解释它。</p>
<h3>Cookie</h3>
<p>顾名思义，他会发送你浏览器中存储的Cookie信息给服务器。</p>
<p><code>Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120; foo=bar</code></p>
<p>它是用分号分割的一组名值对。Cookie也可以包含session id。</p>
<p>在PHP中，单一的Cookie可以访问$_COOKIE数组获得。你可以直接用$_SESSION array获取session变量。如果你需要session id，那么你可以使用session_id()函数代替cookie。</p>
<p><code>echo $_COOKIE['foo'];<br />
// output: bar<br />
echo $_COOKIE['PHPSESSID'];<br />
// output: r2t5uvjq435r4q7ib3vtdjq120<br />
session_start();<br />
echo session_id();<br />
// output: r2t5uvjq435r4q7ib3vtdjq120</code></p>
<h3>Referer</h3>
<p>顾名思义, 头部将会包含referring url信息。</p>
<p>例如，我访问Nettuts+的主页并点击了一个链接，这个头部信息将会发送到浏览器：<br />
<code>Referer: http://net.tutsplus.com/ </code></p>
<p>在PHP中，可以通过 $_SERVER['HTTP_REFERER'] 获取该值。</p>
<p><code>if (isset($_SERVER['HTTP_REFERER'])) {<br />
$url_info = parse_url($_SERVER['HTTP_REFERER']);<br />
// is the surfer coming from Google?<br />
if ($url_info['host'] == 'www.google.com') {<br />
parse_str($url_info['query'], $vars);<br />
echo "You searched on Google for this keyword: ". $vars['q'];<br />
}<br />
}<br />
// if the referring url was:<br />
// http://www.google.com/search?source=ig&amp;hl=en&amp;rlz=&amp;=&amp;q=http+headers&amp;aq=f&amp;oq=&amp;aqi=g-p1g9<br />
// the output will be:<br />
// You searched on Google for this keyword: http headers</code></p>
<p>You may have noticed the word &#8220;referrer&#8221; is misspelled as &#8220;referer&#8221;. Unfortunately it made into the official HTTP specifications like that and got stuck.</p>
<h3>Authorization</h3>
<p>当一个页面需要授权，浏览器就会弹出一个登陆窗口，输入正确的帐号后，浏览器会发送一个HTTP请求，但此时会包含这样一个头部：</p>
<p><code>Authorization: Basic bXl1c2VyOm15cGFzcw==</code></p>
<p>包含在头部的这部分信息是base64 encoded。例如，base64_decode(&#8216;bXl1c2VyOm15cGFzcw==&#8217;) 会被转化为 ‘myuser:mypass’ 。</p>
<p>在PHP中，这个值可以用$_SERVER['PHP_AUTH_USER'] 和 $_SERVER['PHP_AUTH_PW'] 获得。</p>
<p>更多细节我们会在WWW-Authenticate部分讲解。</p>
<h2 style="font-size: 1.5em; ">HTTP Headers 中的 HTTP响应</h2>
<p>现在让我了解一些常见的HTTP Headers中的HTTP响应信息。</p>
<p>在PHP中，你可以通过 <a href="http://php.net/manual/en/function.header.php">header()</a> 来设置头部响应信息。PHP已经自动发送了一些必要的头部信息，如 载入的内容，设置 cookies 等等&#8230; 你可以通过 <a href="http://www.php.net/manual/en/function.headers-list.php">headers_list()</a> 函数看到已发送和将要发送的头部信息。你也可以使用<a href="http://www.php.net/manual/en/function.headers-sent.php">headers_sent()</a>函数来检查头部信息是否已经被发送。</p>
<h3>Cache-Control</h3>
<p>w3.org 的定义是：“The Cache-Control general-header field is used to specify directives which MUST be obeyed by all caching mechanisms along the request/response chain.” 其中“caching mechanisms” 包含一些你ISP可能会用到的 网关和代理信息。</p>
<p>例如：</p>
<p><code>Cache-Control: max-age=3600, public</code></p>
<p>“public”意味着这个响应可以被任何人缓存，“max-age” 则表明了该缓存有效的秒数。允许你的网站被缓存降大大减少下载时间和带宽，同时也提高的浏览器的载入速度。</p>
<p>也可以通过设置 “no-cache”  指令来禁止缓存：</p>
<p><code>Cache-Control: no-cache </code></p>
<p>更多详情请参见<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9">w3.org</a>。</p>
<h3>Content-Type</h3>
<p>这个头部包含了文档的&#8221;mime-type&#8221;。浏览器将会依据该参数决定如何对文档进行解析。例如，一个html页面（或者有html输出的php页面）将会返回这样的东西：</p>
<p><code>Content-Type: text/html; charset=UTF-8</code></p>
<p><span><span>‘text’ 是文档类型，‘html’则是文档子类型。 这个头部还包括了更多信息，例如 charset。</span></span></p>
<p><span><span>如果是一个图片，将会发送这样的响应：</span></span></p>
<p><code>Content-Type: image/gif</code></p>
<p>浏览器可以通过mime-type来决定使用外部程序还是自身扩展来打开该文档。如下的例子降调用Adobe Reader：</p>
<p><code>Content-Type: application/pdf</code></p>
<p>直接载入，Apache通常会自动判断文档的mime-type并且添加合适的信息到头部去。并且大部分浏览器都有一定程度的容错，在头部未提供或者错误提供该信息的情况下它会去自动检测mime-type。</p>
<p>你可以在<a href="http://www.webmaster-toolkit.com/mime-types.shtml" target="_blank">这里</a>找到一个常用mime-type列表。</p>
<p>在PHP中你可以通过 <a href="http://www.php.net/manual/en/function.finfo-file.php">finfo_file()</a> 来检测文件的ime-type。</p>
<h3>Content-Disposition</h3>
<p>这个头部信息将告诉浏览器打开一个文件下载窗口，而不是试图解析该响应的内容。例如：</p>
<p><code>Content-Disposition: attachment; filename="download.zip"</code></p>
<p>他会导致浏览器出现这样的对话框：</p>
<p><img class="alignnone" src="http://nettuts.s3.amazonaws.com/511_http/download.png" alt="" /></p>
<p>注意，适合它的Content-Type头信息同时也会被发送</p>
<p><code>Content-Type: application/zip<br />
Content-Disposition: attachment; filename="download.zip"</code></p>
<h3>Content-Length</h3>
<p>当内容将要被传输到浏览器时，服务器可以通过该头部告知浏览器将要传送文件的大小（bytes）。</p>
<p><code>Content-Length: 89123</code></p>
<p><span><span>对于文件下载来说这个信息相当的有用。这就是为什么浏览器知道下载进度的原因。</span></span></p>
<p><span><span>例如，这里我写了一段虚拟脚本，来模拟一个慢速下载。</span></span></p>
<p><code>// it's a zip file<br />
header('Content-Type: application/zip');<br />
// 1 million bytes (about 1megabyte)<br />
header('Content-Length: 1000000');<br />
// load a download dialogue, and save it as download.zip<br />
header('Content-Disposition: attachment; filename="download.zip"');<br />
// 1000 times 1000 bytes of data<br />
for ($i = 0; $i &lt; 1000; $i++) {<br />
<span style="white-space:pre"> </span>echo str_repeat(".",1000);<br />
<span style="white-space:pre"> </span>// sleep to slow down the download<br />
<span style="white-space:pre"> </span>usleep(50000);<br />
}</code></p>
<p>结果将会是这样的：</p>
<p><img class="alignnone" src="http://nettuts.s3.amazonaws.com/511_http/download_with_progress.png" alt="" /></p>
<p>现在，我将Content-Length头部注释掉：</p>
<p><code>// it's a zip file<br />
header('Content-Type: application/zip');<br />
// the browser won't know the size<br />
// header('Content-Length: 1000000');<br />
// load a download dialogue, and save it as download.zip<br />
header('Content-Disposition: attachment; filename="download.zip"');<br />
// 1000 times 1000 bytes of data<br />
for ($i = 0; $i &lt; 1000; $i++) {<br />
<span style="white-space:pre"> </span>echo str_repeat(".",1000);<br />
<span style="white-space:pre"> </span>// sleep to slow down the download<br />
<span style="white-space:pre"> </span>usleep(50000);<br />
}</code></p>
<p>结果就变成了这样：</p>
<p><img class="alignnone" src="http://nettuts.s3.amazonaws.com/511_http/download_without_progress.png" alt="" /></p>
<p>这个浏览器只会告诉你已下载了多少，但不会告诉你总共需要下载多少。而且进度条也不会显示进度。</p>
<h3>Etag</h3>
<p>这是另一个为缓存而产生的头部信息。它看起来会是这样：</p>
<p><code>Etag: "pub1259380237;gz"</code></p>
<p><span><span>服务器可能会将该信息和每个被发送文件一起响应给浏览器。该值可以包含文档的最后修改日期，文件大小或者文件校验和。浏览会把它和所接收到的文档一起缓存。下一次当浏览器再次请求同一文件时将会发送如下的HTTP请求：</span></span></p>
<p><code>If-None-Match: "pub1259380237;gz"</code></p>
<p>如果所请求的文档Etag值和它一致，服务器将会发送304状态码，而不是2oo。并且不返回内容。浏览器此时就会从缓存加载该文件。</p>
<h3>Last-Modified</h3>
<p>顾名思义，这个头部信息用GMT格式表明了文档的最后修改时间：</p>
<p><code>Last-Modified: Sat, 28 Nov 2009 03:50:37 GMT</code></p>
<p><code>$modify_time = filemtime($file);<br />
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $modify_time) . " GMT");</code></p>
<p>它提供了另一种缓存机制。浏览器可能会发送这样的请求：</p>
<p><code>If-Modified-Since: Sat, 28 Nov 2009 06:38:19 GMT</code></p>
<p><span><span>在If-Modified-Since一节我们已经讨论过了。</span></span></p>
<h3>Location</h3>
<p>这个头部是用来重定向的。如果响应代码为 301 或者 302 ，服务器就必须发送该头部。例如，当你访问 http://www.nettuts.com 时浏览器就会收到如下的响应：</p>
<p><code>HTTP/1.x 301 Moved Permanently<br />
...<br />
Location: http://net.tutsplus.com/<br />
...</code></p>
<p>在PHP中你可以通过这种方式对访客重定向：<br />
<code>header('Location: http://net.tutsplus.com/');</code></p>
<p><span>默认会发送302状态码，如果你想发送301，就这样写：</span></p>
<p><code>header('Location: http://net.tutsplus.com/', true, 301);</code></p>
<h3>Set-Cookie</h3>
<p>当一个网站需要设置或者更新你浏览的cookie信息时，它就会使用这样的头部：</p>
<p><code>Set-Cookie: skin=noskin; path=/; domain=.amazon.com; expires=Sun, 29-Nov-2009 21:42:28 GMT<br />
Set-Cookie: session-id=120-7333518-8165026; path=/; domain=.amazon.com; expires=Sat Feb 27 08:00:00 2010 GMT</code></p>
<p>每个cookie会作为单独的一条头部信息。注意，通过js设置cookie将不会体现在HTTP头中。</p>
<p>在PHP中，你可以通过<a href="http://php.net/manual/en/function.setcookie.php">setcookie()</a>函数来设置cookie，PHP会发送合适的HTTP 头。</p>
<p><code>setcookie("TestCookie", "foobar");</code></p>
<p>它会发送这样的头信息：</p>
<p><code>Set-Cookie: TestCookie=foobar</code></p>
<p>如果未指定到期时间，cookie就会在浏览器关闭后被删除。</p>
<h3>WWW-Authenticate</h3>
<p>一个网站可能会通过HTTP发送这个头部信息来验证用户。当浏览器看到头部有这个响应时就会打开一个弹出窗。</p>
<p><code>WWW-Authenticate: Basic realm="Restricted Area"</code></p>
<p>它会看起来像这样：</p>
<p><img class="alignnone" src="http://nettuts.s3.amazonaws.com/511_http/401_prompt.png" alt="" /></p>
<p>在<a href="http://nettuts.s3.amazonaws.com/511_http/401_prompt.png" target="_blank">PHP手册的一章</a>中就有一段简单的代码演示了如果用PHP做这样的事情：</p>
<p><code>if (!isset($_SERVER['PHP_AUTH_USER'])) {<br />
header('WWW-Authenticate: Basic realm="My Realm"');<br />
header('HTTP/1.0 401 Unauthorized');<br />
echo 'Text to send if user hits Cancel button';<br />
exit;<br />
} else {<br />
echo "&lt;p&gt;Hello {$_SERVER['PHP_AUTH_USER']}.&lt;/p&gt;";<br />
echo "&lt;p&gt;You entered {$_SERVER['PHP_AUTH_PW']} as your password.&lt;/p&gt;";<br />
}</code></p>
<h3>Content-Encoding</h3>
<p>这个头部通常会在返回内容被压缩时设置。</p>
<p><code>Content-Encoding: gzip</code></p>
<p>在PHP中，如果你调用了<a href="http://www.php.net/manual/en/function.ob-gzhandler.php">ob_gzhandler()</a>函数，这个头部将会自动被设置。</p>
]]></content:encoded>
			<wfw:commentRss>http://rlog.cn/?feed=rss2&amp;p=521</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
	</channel>
</rss>
