<?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>MoDoFo.println(" &#187; 翻译</title>
	<atom:link href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91/feed" rel="self" type="application/rss+xml" />
	<link>http://zhangv.com</link>
	<description>Life for Idea - forever young</description>
	<lastBuildDate>Sat, 07 Apr 2012 04:08:37 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>初创公司CEO应该遵守的14条准则</title>
		<link>http://zhangv.com/archives/1664</link>
		<comments>http://zhangv.com/archives/1664#comments</comments>
		<pubDate>Sun, 02 Jan 2011 05:47:15 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[非技术(non-tech)]]></category>
		<category><![CDATA[ceo]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[startups]]></category>
		<category><![CDATA[创业]]></category>

		<guid isPermaLink="false">http://zhangv.com/?p=1664</guid>
		<description><![CDATA[
初创公司CEO应该遵守的14条准则
(14 Ways To Be A Great Startup CEO - http://onstartups.com/tabid/3339/bid/34321/14-Ways-To-Be-A-Great-Startup-CEO.aspx)



初创公司的CEO生活并非我们想像的那么光鲜, 初创公司的生活也许也并非像媒体报道的那样多彩. 你知道我在指哪些媒体...那些谈论融资是多么容易,用户量扩大到多少,做CEO有多好. 很少能听到做CEO多么"操蛋"以及每个创始人都不想成为企业家. 我最近花了一些时间思考如何成为一个创始人兼CEO, 下面是一些结果.

公司愿景的守护者

作为CEO,必须要时刻守护着公司的愿景. 我不是说几个月之后的计划,而是非常远的愿景. CEO要确保所有事务都在正确的轨道从而达到季度目标, 一个初创公司的世界观改变是无法在1年甚至10年完成的, 就像Google. 所以一个伟大的CEO要常常评估新的项目是否适应公司长远的发展.
团队的保护伞

初创公司的CEO需要成为团队的巫毒人偶. 他们必须能够在承受巨大的压力,痛苦和折磨的同时做出明智的决定. 绝对不能让团队肩负过多的压力和担忧. 一个好的CEO会消化这些压力,然后让团队继续前进,同时还要假装这些压力从来都不存在 - 这并不是说他要隐藏或者对团队撒谎. 没有必要让团队的每个人每天都承担着巨大的压力工作, 这些都应该让CEO来.
找到最聪明的人

初创公司的CEO必须要有找到最优秀的人的诀窍. 其中关键是找到比自己在某一方面更优秀的人. 可能是技术尖兵/领袖,也可能是一个新的业务拓展副总裁. CEO必须要找到这些人并且马上把他们整合到自己的团队. 同时还要有激情去劝说他们离开目前工作(通常意味着更好的薪水和待遇)加入公司. 当然真正的关键是在雇佣之后, CEO要给予他们极大的信任并委派给他们最擅长的事情. 放权是很困难的,尤其是在公司刚刚开始成长时候.
公司和投资人之间的协调人

无论你是否相信, 你并非投资人的唯一投资. 即使你是超级明星, 投资人也有大把极具潜力的公司要投. 好的投资人每年都要选择2-3个新公司. 初创公司CEO要成为让投资人清楚公司目前的进展和主要问题,包括任何投资人需要(想要)了解的事情.想要融资的初创公司董事会必须要有3个人:CEO创始人, 投资人, 独立董事. 你是你合伙人和员工的唯一代表.

公司和产品之间的衔接人

对我来说一个坚定不移的事实是:好的公司必须要创始人兼任CEO. 并不是他们有权利成为CEO,而是因为CEO必须要非常了解公司产品愿景. 创始人最了解这些并能自始至终的贯彻这一愿景. 这就需要COO,其他董事会成员,部门负责人来填补管理上的空白. Facebook就是用了这样的策略,同时也是Apple公司在jobs带领下再次崛起的原因. 都是让CEO尽可能地专注于产品.
能够从工作中学习

大多数CEO并非MBA或是具备让公司成功的背景. 最成功的往往是那些能够从失败中学习并不断提升自己领导才能的人. Zuckburger是从19岁开始的,七年后拥有现在最强大的互联网公司.不要担心你是否够格, 你会在过程中获得最核心的东西. 成功的CEO让优秀的导师围在身边为自己护航.
没有经验反而更好

零经验的初创公司CEO通常会更好,如果你一开始就带着先入为主的想法并排除任何创始人应该有的生气,反而不好.传统教育告诉你如何成为一个大啊大公司的CEO或经理人,而不会告诉你如何成为50人以下的初创公司的CEO.这完全是两种公司,需要截然不同的领导方法.
对"说不"不反感

你会收到来自潜在合作者,员工,投资人洪水般的建议.所有的都听起来不错. 你也许有足够的资源来执行它们.但是先不要急,说"是"很容易,说"不"很难. 不要舍不得说"不",你可以保持你的公司在事先确定的轨道. 也可以保持你的团队长时间专注于一件事并有更多的成就感. 我见过太多的初创公司失败 [...]]]></description>
			<content:encoded><![CDATA[<div><span style="font-family: 微软雅黑; font-size: small;"><span style="line-height: normal;"></p>
<div><span style="border-collapse: separate; color: #000000; font-family: 微软雅黑; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium;">初创公司CEO应该遵守的14条准则</span></div>
<div><span style="border-collapse: separate; color: #000000; font-family: 微软雅黑; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium;">(<span style="font-size: 15px; font-weight: bold;"><a href="http://onstartups.com/tabid/3339/bid/34321/14-Ways-To-Be-A-Great-Startup-CEO.aspx">14 Ways To Be A Great Startup CEO</a> - </span>http://onstartups.com/tabid/3339/bid/34321/14-Ways-To-Be-A-Great-Startup-CEO.aspx)</span></div>
<div>
<div>
<img style="cursor: default; vertical-align: middle;" src="file:///C:/Users/wei/AppData/Local/Temp/enhtmlclip/Image.jpg" border="0" alt="great startup ceo mark zuckerberg resized 600" /></div>
<div>初创公司的CEO生活并非我们想像的那么光鲜, 初创公司的生活也许也并非像媒体报道的那样多彩. 你知道我在指哪些媒体...那些谈论融资是多么容易,用户量扩大到多少,做CEO有多好. 很少能听到做CEO多么"操蛋"以及每个创始人都不想成为企业家. 我最近花了一些时间思考如何成为一个创始人兼CEO, 下面是一些结果.</div>
<div><span id="more-1664"></span></div>
<h2>公司愿景的守护者</h2>
</div>
<div>作为CEO,必须要时刻守护着公司的愿景. 我不是说几个月之后的计划,而是非常远的愿景. CEO要确保所有事务都在正确的轨道从而达到季度目标, 一个初创公司的世界观改变是无法在1年甚至10年完成的, 就像Google. 所以一个伟大的CEO要常常评估新的项目是否适应公司长远的发展.</p>
<h2>团队的保护伞</h2>
</div>
<div>初创公司的CEO需要成为团队的巫毒人偶. 他们必须能够在承受巨大的压力,痛苦和折磨的同时做出明智的决定. 绝对不能让团队肩负过多的压力和担忧. 一个好的CEO会消化这些压力,然后让团队继续前进,同时还要假装这些压力从来都不存在 - 这并不是说他要隐藏或者对团队撒谎. 没有必要让团队的每个人每天都承担着巨大的压力工作, 这些都应该让CEO来.</p>
<h2>找到最聪明的人</h2>
</div>
<div>初创公司的CEO必须要有找到最优秀的人的诀窍. 其中关键是找到比自己在某一方面更优秀的人. 可能是技术尖兵/领袖,也可能是一个新的业务拓展副总裁. CEO必须要找到这些人并且马上把他们整合到自己的团队. 同时还要有激情去劝说他们离开目前工作(通常意味着更好的薪水和待遇)加入公司. 当然真正的关键是在雇佣之后, CEO要给予他们极大的信任并委派给他们最擅长的事情. 放权是很困难的,尤其是在公司刚刚开始成长时候.</p>
<h2>公司和投资人之间的协调人</h2>
</div>
<div>无论你是否相信, 你并非投资人的唯一投资. 即使你是超级明星, 投资人也有大把极具潜力的公司要投. 好的投资人每年都要选择2-3个新公司. 初创公司CEO要成为让投资人清楚公司目前的进展和主要问题,包括任何投资人需要(想要)了解的事情.想要融资的初创公司董事会必须要有3个人:CEO创始人, 投资人, 独立董事. 你是你合伙人和员工的唯一代表.</div>
<div>
<h2>公司和产品之间的衔接人</h2>
</div>
<div>对我来说一个坚定不移的事实是:好的公司必须要创始人兼任CEO. 并不是他们有权利成为CEO,而是因为CEO必须要非常了解公司产品愿景. 创始人最了解这些并能自始至终的贯彻这一愿景. 这就需要COO,其他董事会成员,部门负责人来填补管理上的空白. Facebook就是用了这样的策略,同时也是Apple公司在jobs带领下再次崛起的原因. 都是让CEO尽可能地专注于产品.</p>
<h2>能够从工作中学习</h2>
</div>
<div>大多数CEO并非MBA或是具备让公司成功的背景. 最成功的往往是那些能够从失败中学习并不断提升自己领导才能的人. Zuckburger是从19岁开始的,七年后拥有现在最强大的互联网公司.不要担心你是否够格, 你会在过程中获得最核心的东西. 成功的CEO让优秀的导师围在身边为自己护航.</p>
<h2>没有经验反而更好</h2>
</div>
<div>零经验的初创公司CEO通常会更好,如果你一开始就带着先入为主的想法并排除任何创始人应该有的生气,反而不好.传统教育告诉你如何成为一个大啊大公司的CEO或经理人,而不会告诉你如何成为50人以下的初创公司的CEO.这完全是两种公司,需要截然不同的领导方法.</p>
<h2>对"说不"不反感</h2>
</div>
<div>你会收到来自潜在合作者,员工,投资人洪水般的建议.所有的都听起来不错. 你也许有足够的资源来执行它们.但是先不要急,说"是"很容易,说"不"很难. 不要舍不得说"不",你可以保持你的公司在事先确定的轨道. 也可以保持你的团队长时间专注于一件事并有更多的成就感. 我见过太多的初创公司失败 - 仅仅因为CEO不停地切换产品方向.</p>
<h2>拥有一些技术知识</h2>
</div>
<div>好的初创CEO不应该惧怕代码和文本编辑器. 他们不需要每天扎入代码堆里,但是他们必须要懂技术需求. 说"去做吧"很容易,但真正做是另一回事.很多看起来简单的事情也许意味着大量的技术挑战.雇佣一些早期的技术团队成员也是很有帮助的.</p>
<h2>能够将事情分而治之</h2>
</div>
<div>奇怪的是它只对你和你的合伙人有意义. 你要把它细化为足够的大小和阶段以便让团队明白如何实施. 你还要知道何时何地有策略地处理事情.根据现有资源应该先做那件事情?</div>
<div>
<h2>总能想方设法想出新的解决办法</h2>
<div>没有什么事是顺风顺水的. 好事落空,人员流失,坏事登门,服务器宕机以及各种"爆胎".你要迅速解决他们. 橄榄球场上常说的一句话:</div>
<div>"当四分卫已经走到争球线外, 看到防守方已经推进到他没想到的地方,大声叫出新的方案."</div>
<div>你会遇到没想到的各种事情,并能想出解决方法, 快速行动,花更多钱甚至丢弃整个项目.</div>
<h2>能够激励团队走出失望的阴影</h2>
</div>
<div>人们喜欢谈论各种负面新闻,尤其是在公司陷入困境时. 出色的CEO能够承担那些来自公众的失望并让团队保持专注.他们能够揭露谣言甚至为了团队正面出击. 可以通过5分钟的讲话或一封邮件. 最差的解决办法是逃避或者被动防御. 我再重复一遍: 不要畏缩!!</p>
<h2>出色的沟通者</h2>
</div>
<div>你要能够每天不停的描述出你感觉到别人的激情和能量. 作为创始人你必须将团队的愿景和未来期望传达给外边的世界.你要能够把伟大愿景诠释成平常人可以理解的东西. 不要用疯狂的技术行话或行业术语. 要简单,清晰,令人信服. 同时要能够为自己的观点争辩. 很多人会挑战你,试探你有多强大的意志力. 尊敬别人,对自己的答案自信.虽然经常出错,但绝不迟疑.</p>
<h2>不要搞"无为而治"</h2>
<div><span style="border-collapse: separate; color: #000000; font-family: 微软雅黑; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium;"><a href="http://techcrunch.com/2009/10/24/startup-school-mark-pincus-talks-about-becoming-a-great-ceo-with-tony-robbins-help/">Mark Pincus,</a></span><a href="http://techcrunch.com/2009/10/24/startup-school-mark-pincus-talks-about-becoming-a-great-ceo-with-tony-robbins-help/">Zynga</a><a href="http://techcrunch.com/2009/10/24/startup-school-mark-pincus-talks-about-becoming-a-great-ceo-with-tony-robbins-help/">的CEO, 举了一个很好的例子来说明不要成为一个"不作为"的CEO,</a> 简单的说, 担心那些有产出的事情,而不是虚名. 如果在开会/面试/完成交易中选择,选择后者,而不是"留给某某某". 不要怕做打杂的.</div>
<div>无疑这是个冗长的清单, 也许还并不直观. 哪些你曾经见过或经历过? 也许CEO的工作并不怎么样,不是么?</div>
<p>作者 Twitter: <a title="http://www.twitter.com/jasonlbaptiste" href="http://www.twitter.com/jasonlbaptiste" target="_self">http://www.twitter.com/jasonlbaptiste</a>, Facebook: <a title="http://www.facebook.com/jasonlbaptiste" href="http://www.facebook.com/jasonlbaptiste" target="_self">http://www.facebook.com/jasonlbaptiste</a>, 邮件: <a title="jbaptiste@onstartups.com" href="mailto:jbaptiste@onstartups.com" target="_self">jbaptiste@onstartups.com</a>, 电话: 201.305.0552</div>
<p></span></span></div>

	Tags: <a href="http://zhangv.com/archives/tag/ceo" title="ceo" rel="tag">ceo</a>, <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/startups" title="startups" rel="tag">startups</a>, <a href="http://zhangv.com/archives/tag/%e5%88%9b%e4%b8%9a" title="创业" rel="tag">创业</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/1664/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]API设计黄金法则</title>
		<link>http://zhangv.com/archives/1544</link>
		<comments>http://zhangv.com/archives/1544#comments</comments>
		<pubDate>Mon, 02 Aug 2010 06:21:02 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[设计]]></category>

		<guid isPermaLink="false">http://zhangv.com/archives/1544</guid>
		<description><![CDATA[API设计黄金法则
原文: http://programmer.97things.oreilly.com/wiki/index.php/The_Golden_Rule_of_API_Design
API的设计通常是一项艰巨的任务,尤其当设计的API非常庞大时. 如果你设计的API将会有成百上千的用户时,你要考虑今后应该如何扩展来避免不小心把客户端的代码搞挂. 除此之外,你还要考虑用户在使用API的过程中对你的影响.如果你的API类使用它内部的一个方法时,你要记得 - 用户可以通过子类复写(override)他,而这,可能会是灾难性的. 你将不能修改那些方法,因为用户已经这样使用它们了. 你今后的内部实现将无可避免的由你的用户来决定,而不再是你.
API程序员有各种各样的方法来解决这个问题,但最简单的还是禁止用户修改API.如果你用的是Java你可能会把所有的类都声明为final,如果用C#,则声明所有的方法为sealed.无论用什么语言,你都可以通过单例(singleton)或者静态工厂方法来避免用户复写代码,或者不当的扩展和使用你的代码.这些听起来很有道理,但,真是这样吗?
在过去的10年,我们渐渐意识到单元测试是一种非常非常重要的实践,但这一实践却并没有完全被整个行业所认可. 显而易见的是,大多数情况下,为一个未经测试的类编写测试用例时总是很难.你会发现使用了API的代码和API耦合的就像是上了强力胶一样.没有办法去模拟API类的行为,进而容易的测试API和你的代码之间的交互.
经过一段时间后也许会有改善,但只有我们在开始设计API时就考虑到测试问题.不幸的是,这可能需要你(API的设计者)多花一点时间 - 不仅测试自己的代码,还要考虑用户如何测试他们的代码. 这里就引出了伟大的"API设计黄金法则": 仅仅给API写测试用例是不够的;你还要为使用API的代码写单元测试.只有这样做了,你才会在第一时间体会用户在使用你的API时进行测试时的种种问题.
让API易于测试的方法有很多.static,final和sealed并不见得是不合理的,他们有相应的使用场景.但意识到测试问题是很重要的,最好的办法就是自己去感受.一旦你这样做了,你将更加胜任各种设计挑战.
By Michael Feathers

	Tags: API, 程序员, 翻译, 设计
]]></description>
			<content:encoded><![CDATA[<p>API设计黄金法则</p>
<p>原文: http://programmer.97things.oreilly.com/wiki/index.php/The_Golden_Rule_of_API_Design<br />
API的设计通常是一项艰巨的任务,尤其当设计的API非常庞大时. 如果你设计的API将会有成百上千的用户时,你要考虑今后应该如何扩展来避免不小心把客户端的代码搞挂. 除此之外,你还要考虑用户在使用API的过程中对你的影响.如果你的API类使用它内部的一个方法时,你要记得 - 用户可以通过子类复写(override)他,而这,可能会是灾难性的. 你将不能修改那些方法,因为用户已经这样使用它们了. 你今后的内部实现将无可避免的由你的用户来决定,而不再是你.</p>
<p>API程序员有各种各样的方法来解决这个问题,但最简单的还是禁止用户修改API.如果你用的是Java你可能会把所有的类都声明为final,如果用C#,则声明所有的方法为sealed.无论用什么语言,你都可以通过单例(singleton)或者静态工厂方法来避免用户复写代码,或者不当的扩展和使用你的代码.这些听起来很有道理,但,真是这样吗?</p>
<p>在过去的10年,我们渐渐意识到单元测试是一种非常非常重要的实践,但这一实践却并没有完全被整个行业所认可. 显而易见的是,大多数情况下,为一个未经测试的类编写测试用例时总是很难.你会发现使用了API的代码和API耦合的就像是上了强力胶一样.没有办法去模拟API类的行为,进而容易的测试API和你的代码之间的交互.</p>
<p>经过一段时间后也许会有改善,但只有我们在开始设计API时就考虑到测试问题.不幸的是,这可能需要你(API的设计者)多花一点时间 - 不仅测试自己的代码,还要考虑用户如何测试他们的代码. 这里就引出了伟大的"API设计黄金法则": 仅仅给API写测试用例是不够的;你还要为使用API的代码写单元测试.只有这样做了,你才会在第一时间体会用户在使用你的API时进行测试时的种种问题.</p>
<p>让API易于测试的方法有很多.static,final和sealed并不见得是不合理的,他们有相应的使用场景.但意识到测试问题是很重要的,最好的办法就是自己去感受.一旦你这样做了,你将更加胜任各种设计挑战.</p>
<p>By Michael Feathers</p>

	Tags: <a href="http://zhangv.com/archives/tag/api" title="API" rel="tag">API</a>, <a href="http://zhangv.com/archives/tag/%e7%a8%8b%e5%ba%8f%e5%91%98" title="程序员" rel="tag">程序员</a>, <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/%e8%ae%be%e8%ae%a1" title="设计" rel="tag">设计</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/1544/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>规划你的WebAPI &#8211; 安全</title>
		<link>http://zhangv.com/archives/1233</link>
		<comments>http://zhangv.com/archives/1233#comments</comments>
		<pubDate>Fri, 28 Aug 2009 02:56:02 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[openAPI]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[SOAP]]></category>

		<guid isPermaLink="false">http://zhangv.com/archives/1233</guid>
		<description><![CDATA[


  

译自“Professional Web APIs with PHP: eBay,Google, PayPal, Amazon, FedEx, Plus Web Feeds” (chapter 12)

你一定听过这样一句话“失败的计划是必定失败（Fail to plan, and you plan to fail.”对WebAPI来说，在开始一切工作之前的规划尤为重要，因为他不仅会影响到实现难度，同时会让那些使用API的开发者痛苦不堪。



通常来说，引入额外的安全层次会更好的保护你的API，但是同时需要很好的平衡这种设计对易用性的影响。时刻记得，安全即是保护你的数据，也是确保开发者的调用过程完整（通常是用“token”）。
完全开放的API
在一个完全没有安全验证机制的开放API里，首先会有一个来自外界的请求，然后系统会尝试完成并响应这个请求。
优点:

最小的使用障碍 – 既没有加密页没有验证机制，任何人都可以访问你的API。
更容易的创建分布式应用 – 登录帐户或者程序员，只要他们使用了你的API，那么程序可以分布到任何地方,而你根本无需考虑他们在哪里调用。
省心 – 如果你没有管理用户账户和开发密钥，那就可以花更多的时间在开发API本身。

缺点:

缺少控制 – 任何人在任何地方都可以调用API，尽管这是web服务的目标，但可能会在潮水般的请求涌来时失去控制。如果这些请求只是来自一部机器，还可以借助防火墙来搞定，但是如果分布很广，处理起来就会很痛苦。
没有加密 – 所有请求端和服务端的请求和响应都是对任何人都可见的。
无法接触到开发者 – 因为API的调用不存在注册过程，也就无法联络到相应的开发者。而你可以通过注册机制建立一个与开发者的一个很好的联系。比如，告知他的应用正在被误用，API有新的改动，征求改进建议等等。
误用 – 很不幸，总有一些人会利用这一点去做一些不好的事，即便你觉得这个可能性很小。

因为这些问题，完全开放的API只适用于用来请求信息，而不是发布信息 – 也就是请求的信息资源产生过程不会占用太多CPU资源。一个很恰当的例子是国家天气服务API，它只接受信息请求，并且这些请求可以全天候的缓存在服务器上。如果是需要发布信息，那么相应的验证机制要被用来识别请求者，当请求需要消耗大量CPU时，远端程序需要被识别出来，从而对发来的请求进行过滤和控制。
HTTP 验证
通过HTTP头包含中验证信息，基于Base64编码，实际上并没有加密，没有信息安全可言。
优点：

简单 — 因为验证信息是在HTTP头里，所以可以被路由器和网关处理。从而可以用硬件过滤和筛查客户端请求。从应用的角度来看，验证实际上是发生在服务器端，因此设计服务器时应该考虑到高性能和高并发的开发和测试。
对应用来说透明     -&#160; 因为是web服务器来处理验证，你可以完全不需要考虑用户登录问题。当然这只适用于请求那些于特定用户无关的信息（每个用户使用相同的请求得到相同的信息）。
易于编码 — 添加一个额外的HTTP头信息对大多数编程语言来说都不在话下。It is also    [...]]]></description>
			<content:encoded><![CDATA[<link rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml">
<link rel="themeData" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx">
<link rel="colorSchemeMapping" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml"><!--[if gte mso 9]><xml> <w:WordDocument>  <w:View>Normal</w:View>  <w:Zoom>0</w:Zoom>  <w:TrackMoves/>  <w:TrackFormatting/>  <w:PunctuationKerning/>  <w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing>  <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery>  <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery>  <w:ValidateAgainstSchemas/>  <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>  <w:IgnoreMixedContent>false</w:IgnoreMixedContent>  <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>  <w:DoNotPromoteQF/>  <w:LidThemeOther>EN-US</w:LidThemeOther>  <w:LidThemeAsian>ZH-CN</w:LidThemeAsian>  <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>  <w:Compatibility>   <w:SpaceForUL/>   <w:BalanceSingleByteDoubleByteWidth/>   <w:DoNotLeaveBackslashAlone/>   <w:ULTrailSpace/>   <w:DoNotExpandShiftReturn/>   <w:AdjustLineHeightInTable/>   <w:BreakWrappedTables/>   <w:SnapToGridInCell/>   <w:WrapTextWithPunct/>   <w:UseAsianBreakRules/>   <w:DontGrowAutofit/>   <w:SplitPgBreakAndParaMark/>   <w:DontVertAlignCellWithSp/>   <w:DontBreakConstrainedForcedTables/>   <w:DontVertAlignInTxbx/>   <w:Word11KerningPairs/>   <w:CachedColBalance/>   <w:UseFELayout/>  </w:Compatibility>  <m:mathPr>   <m:mathFont m:val="Cambria Math"/>   <m:brkBin m:val="before"/>   <m:brkBinSub m:val="&#45;-"/>   <m:smallFrac m:val="off"/>   <m:dispDef/>   <m:lMargin m:val="0"/>   <m:rMargin m:val="0"/>   <m:defJc m:val="centerGroup"/>   <m:wrapIndent m:val="1440"/>   <m:intLim m:val="subSup"/>   <m:naryLim m:val="undOvr"/>  </m:mathPr></w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true"  DefSemiHidden="true" DefQFormat="false" DefPriority="99"  LatentStyleCount="267">  <w:LsdException Locked="false" Priority="0" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Normal"/>  <w:LsdException Locked="false" Priority="9" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="heading 1"/>  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/>  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/>  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/>  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/>  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/>  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/>  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/>  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/>  <w:LsdException Locked="false" Priority="39" Name="toc 1"/>  <w:LsdException Locked="false" Priority="39" Name="toc 2"/>  <w:LsdException Locked="false" Priority="39" Name="toc 3"/>  <w:LsdException Locked="false" Priority="39" Name="toc 4"/>  <w:LsdException Locked="false" Priority="39" Name="toc 5"/>  <w:LsdException Locked="false" Priority="39" Name="toc 6"/>  <w:LsdException Locked="false" Priority="39" Name="toc 7"/>  <w:LsdException Locked="false" Priority="39" Name="toc 8"/>  <w:LsdException Locked="false" Priority="39" Name="toc 9"/>  <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/>  <w:LsdException Locked="false" Priority="10" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Title"/>  <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/>  <w:LsdException Locked="false" Priority="11" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/>  <w:LsdException Locked="false" Priority="22" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Strong"/>  <w:LsdException Locked="false" Priority="20" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/>  <w:LsdException Locked="false" Priority="59" SemiHidden="false"   UnhideWhenUsed="false" Name="Table Grid"/>  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>  <w:LsdException Locked="false" Priority="1" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 1"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 1"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 1"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/>  <w:LsdException Locked="false" Priority="34" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>  <w:LsdException Locked="false" Priority="29" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Quote"/>  <w:LsdException Locked="false" Priority="30" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 1"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 1"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 2"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 2"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 2"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 2"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 2"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 3"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 3"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 3"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 3"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 3"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 4"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 4"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 4"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 4"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 4"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 5"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 5"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 5"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 5"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 5"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 6"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 6"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 6"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 6"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 6"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>  <w:LsdException Locked="false" Priority="19" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>  <w:LsdException Locked="false" Priority="21" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>  <w:LsdException Locked="false" Priority="31" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>  <w:LsdException Locked="false" Priority="32" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>  <w:LsdException Locked="false" Priority="33" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>  <w:LsdException Locked="false" Priority="37" Name="Bibliography"/>  <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> </w:LatentStyles> </xml><![endif]--><br />
<style> <!-- /* Font Definitions */ @font-face 	{font-family:Wingdings; 	panose-1:5 0 0 0 0 0 0 0 0 0; 	mso-font-charset:2; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:0 268435456 0 0 -2147483648 0;} @font-face 	{font-family:宋体; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-alt:SimSun; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 135135232 16 0 262145 0;} @font-face 	{font-family:"Cambria Math"; 	panose-1:2 4 5 3 5 4 6 3 2 4; 	mso-font-charset:1; 	mso-generic-font-family:roman; 	mso-font-format:other; 	mso-font-pitch:variable; 	mso-font-signature:0 0 0 0 0 0;} @font-face 	{font-family:Calibri; 	panose-1:2 15 5 2 2 2 4 3 2 4; 	mso-font-charset:0; 	mso-generic-font-family:swiss; 	mso-font-pitch:variable; 	mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face 	{font-family:"\@宋体"; 	panose-1:2 1 6 0 3 1 1 1 1 1; 	mso-font-charset:134; 	mso-generic-font-family:auto; 	mso-font-pitch:variable; 	mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal 	{mso-style-unhide:no; 	mso-style-qformat:yes; 	mso-style-parent:""; 	margin:0cm; 	margin-bottom:.0001pt; 	text-align:justify; 	text-justify:inter-ideograph; 	mso-pagination:none; 	font-size:10.5pt; 	mso-bidi-font-size:11.0pt; 	font-family:"Calibri","sans-serif"; 	mso-ascii-font-family:Calibri; 	mso-ascii-theme-font:minor-latin; 	mso-fareast-font-family:宋体; 	mso-fareast-theme-font:minor-fareast; 	mso-hansi-font-family:Calibri; 	mso-hansi-theme-font:minor-latin; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-theme-font:minor-bidi; 	mso-font-kerning:1.0pt;} a:link, span.MsoHyperlink 	{mso-style-priority:99; 	color:blue; 	text-decoration:underline; 	text-underline:single;} a:visited, span.MsoHyperlinkFollowed 	{mso-style-noshow:yes; 	mso-style-priority:99; 	color:purple; 	mso-themecolor:followedhyperlink; 	text-decoration:underline; 	text-underline:single;} .MsoChpDefault 	{mso-style-type:export-only; 	mso-default-props:yes; 	mso-bidi-font-family:"Times New Roman"; 	mso-bidi-theme-font:minor-bidi;} /* Page Definitions */ @page 	{mso-page-border-surround-header:no; 	mso-page-border-surround-footer:no;} @page Section1 	{size:612.0pt 792.0pt; 	margin:72.0pt 90.0pt 72.0pt 90.0pt; 	mso-header-margin:36.0pt; 	mso-footer-margin:36.0pt; 	mso-paper-source:0;} div.Section1 	{page:Section1;} /* List Definitions */ @list l0 	{mso-list-id:118303353; 	mso-list-template-ids:1406043308;} @list l0:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l1 	{mso-list-id:352532769; 	mso-list-template-ids:-530546072;} @list l1:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l2 	{mso-list-id:641008087; 	mso-list-template-ids:-1893796460;} @list l2:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l3 	{mso-list-id:834225478; 	mso-list-template-ids:-2028545322;} @list l3:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l4 	{mso-list-id:926228567; 	mso-list-template-ids:-486609992;} @list l4:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l5 	{mso-list-id:965811785; 	mso-list-template-ids:312537776;} @list l5:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l6 	{mso-list-id:1012415445; 	mso-list-template-ids:402574394;} @list l6:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l7 	{mso-list-id:1115368711; 	mso-list-template-ids:1451680916;} @list l7:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l8 	{mso-list-id:1116371370; 	mso-list-template-ids:-1627908980;} @list l9 	{mso-list-id:1193226420; 	mso-list-template-ids:1051742168;} @list l9:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} @list l10 	{mso-list-id:1600068387; 	mso-list-template-ids:-1922687292;} @list l10:level1 	{mso-level-number-format:bullet; 	mso-level-text:; 	mso-level-tab-stop:36.0pt; 	mso-level-number-position:left; 	text-indent:-18.0pt; 	mso-ansi-font-size:10.0pt; 	font-family:Symbol;} ol 	{margin-bottom:0cm;} ul 	{margin-bottom:0cm;} --> </style>
<p><!--[if gte mso 10]><br />
<style> /* Style Definitions */ table.MsoNormalTable 	{mso-style-name:普通表格; 	mso-tstyle-rowband-size:0; 	mso-tstyle-colband-size:0; 	mso-style-noshow:yes; 	mso-style-priority:99; 	mso-style-qformat:yes; 	mso-style-parent:""; 	mso-padding-alt:0cm 5.4pt 0cm 5.4pt; 	mso-para-margin:0cm; 	mso-para-margin-bottom:.0001pt; 	mso-pagination:widow-orphan; 	font-size:10.5pt; 	mso-bidi-font-size:11.0pt; 	font-family:"Calibri","sans-serif"; 	mso-ascii-font-family:Calibri; 	mso-ascii-theme-font:minor-latin; 	mso-hansi-font-family:Calibri; 	mso-hansi-theme-font:minor-latin; 	mso-font-kerning:1.0pt;} </style>
<p> <![endif]-->
<p class="MsoNormal" style="text-align: left;" align="left">译自“<a border="0"><span class="b24-booktitle">Professional Web APIs with PHP: eBay,<br />Google, PayPal, Amazon, FedEx, Plus Web Feeds” (chapter 12)<br /></span></a></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;"><br /></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">你一定听过这样一句话“失败的计划是必定失败（<span lang="EN-US">Fail to plan, and you plan to fail.</span>”对<span lang="EN-US">WebAPI</span>来说，在开始一切工作之前的规划尤为重要，因为他不仅会影响到实现难度，同时会让那些使用<span lang="EN-US">API</span>的开发者痛苦不堪。</span></p>
<p class="MsoNormal" style="text-align: left;" align="left">
<p><span id="more-1233"></span><br /><span style="font-size: 12pt; font-family: 宋体;"><span lang="EN-US"><o:p></o:p></span></span>
</p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">通常来说，引入额外的安全层次会更好的保护你的<span lang="EN-US">API</span>，但是同时需要很好的平衡这种设计对易用性的影响。时刻记得，安全即是保护你的数据，也是确保开发者的调用过程完整（通常是用“<span lang="EN-US">token”</span>）。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="648"></a><a name="ch12lev3sec1"></a><b><span style="font-size: 12pt; font-family: 宋体;">完全开放的<span lang="EN-US">API<o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">在一个完全没有安全验证机制的开放<span lang="EN-US">API</span>里，首先会有一个来自外界的请求，然后系统会尝试完成并响应这个请求。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">优点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">最小的使用障碍 <span lang="EN-US">– </span>既没有加密页没有验证机制，任何人都可以访问你的<span lang="EN-US">API</span>。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">更容易的创建分布式应用 <span lang="EN-US">– </span>登录帐户或者程序员，只要他们使用了你的<span lang="EN-US">API</span>，那么程序可以分布到任何地方<span lang="EN-US">,</span>而你根本无需考虑他们在哪里调用。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">省心 <span lang="EN-US">– </span>如果你没有管理用户账户和开发密钥，那就可以花更多的时间在开发<span lang="EN-US">API</span>本身。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">缺点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">缺少控制 <span lang="EN-US">– </span>任何人在任何地方都可以调用<span lang="EN-US">API</span>，尽管这是<span lang="EN-US">web</span>服务的目标，但可能会在潮水般的请求涌来时失去控制。如果这些请求只是来自一部机器，还可以借助防火墙来搞定，但是如果分布很广，处理起来就会很痛苦。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">没有加密 <span lang="EN-US">– </span>所有请求端和服务端的请求和响应都是对任何人都可见的。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">无法接触到开发者 <span lang="EN-US">– </span>因为<span lang="EN-US">API</span>的调用不存在注册过程，也就无法联络到相应的开发者。而你可以通过注册机制建立一个与开发者的一个很好的联系。比如，告知他的应用正在被误用，<span lang="EN-US">API</span>有新的改动，征求改进建议等等。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">误用 <span lang="EN-US">– </span>很不幸，总有一些人会利用这一点去做一些不好的事，即便你觉得这个可能性很小。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">因为这些问题，完全开放的<span lang="EN-US">API</span>只适用于用来请求信息，而不是发布信息 <span lang="EN-US">– </span>也就是请求的信息资源产生过程不会占用太多<span lang="EN-US">CPU</span>资源。一个很恰当的例子是国家天气服务<span lang="EN-US">API</span>，它只接受信息请求，并且这些请求可以全天候的缓存在服务器上。如果是需要发布信息，那么相应的验证机制要被用来识别请求者，当请求需要消耗大量<span lang="EN-US">CPU</span>时，远端程序需要被识别出来，从而对发来的请求进行过滤和控制。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="650"></a><a name="ch12lev3sec2"></a><b><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">HTTP </span></b><b><span style="font-size: 12pt; font-family: 宋体;">验证<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">通过<span lang="EN-US">HTTP</span>头包含中验证信息，基于<span lang="EN-US">Base64</span>编码，实际上并没有加密，没有信息安全可言。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">优点：<span lang="EN-US"><o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">简单<span lang="EN-US"> — </span>因为验证信息是在<span lang="EN-US">HTTP</span>头里，所以可以被路由器和网关处理。从而可以用硬件过滤和筛查客户端请求。从应用的角度来看，验证实际上是发生在服务器端，因此设计服务器时应该考虑到高性能和高并发的开发和测试。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">对应用来说透明<span lang="EN-US">     -<span style="">&nbsp; </span></span>因为是<span lang="EN-US">web</span>服务器来处理验证，你可以完全不需要考虑用户登录问题。当然这只适用于请求那些于特定用户无关的信息（每个用户使用相同的请求得到相同的信息）。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">易于编码<span lang="EN-US"> — </span>添加一个额外的<span lang="EN-US">HTTP</span>头信息对大多数编程语言来说都不在话下。<span lang="EN-US">It is also     pretty universally available even in shared hosting situations (which may     prevent things like SSL requests or external libraries).<o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">缺点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">验证信息是明文传输的 <span lang="EN-US">—     Base 64</span>是可逆算法，任何人都可以从传输的信息中得到用户名和密码，但实际都不需要这样做，只需要修改<span lang="EN-US">HTTP</span>头即可。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">用户名限制 <span lang="EN-US">— </span>当使用<span lang="EN-US">HTTP</span>验证时，冒号<span lang="EN-US">(:) </span>不可以作为用户名的一部分。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">没有加密<span lang="EN-US"> — </span>所有请求和响应都是可见的。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">这种基本的验证方式对大多数<span lang="EN-US">API</span>应用已经足够了，基本的验证允许<span lang="EN-US">API</span>既可以是客户相关也可以是客户无关的，取决于是否需要。同时允许过滤那些有问题的客户端。更好的办法是将用户名和密码组合分开，这样验证信息可以有点保护，合法用户可以使用其他信息去修改<span lang="EN-US">API</span>的使用权限。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="651"></a><a name="IDX-290"></a><a name="652"></a><a name="ch12lev4sec1"></a><b><span style="font-size: 10pt; font-family: 宋体;">服务器端代码<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">大多数工作都是由<span lang="EN-US">web</span>服务器来完成的。<span lang="EN-US">Apache</span>可以使用一个文本文件查找用户帐号，但如果<span lang="EN-US">API</span>允许用户信息修改，那么这不是一个明智的选择。<span lang="EN-US">Apache</span>可以使用<span lang="EN-US">Berkeley</span>数据库（如果你设置了<span lang="EN-US">mode_db</span>或者<span lang="EN-US">mode_dbm</span>模块），<span lang="EN-US">BerkeleyDB</span>在大多数<span lang="EN-US">linux</span>版本里都是标准组件，如果没有安装，可以从</span><span lang="EN-US"><a href="http://www.sleepvcat.com"><span style="font-size: 12pt; font-family: 宋体;">www.sleepvcat.com</span></a></span><span style="font-size: 12pt; font-family: 宋体;">下载。要使用<span lang="EN-US">BerkeleyDB</span>，<span lang="EN-US">PHP</span>需要配置“<span lang="EN-US">-with –db4</span>”选项，相应<span lang="EN-US">Apache</span>必须要使用“<span lang="EN-US">—enable-module=auth_db</span>”选项编译。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">Httpdconf</span><span style="font-size: 12pt; font-family: 宋体;">要配置为（<span lang="EN-US">(.htaccess</span>也要类似配置<span lang="EN-US">):<o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">&lt;Directory /www/domains/api.example.com &gt;</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>AuthName "API Requires Registration"</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>AuthType Basic</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>AuthDBUserFile /</span><span lang="EN-US"><a href="http://www/basicAuth/api.example.com" target="_top"><span style="font-size: 12pt; font-family: 宋体;">www/basicAuth/api.example.com</span></a></span><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">/passwords.dat</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>require valid-user</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp;</span>&lt;/Directory&gt;</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">Directory</span><span style="font-size: 12pt; font-family: 宋体;">参数指定被保护的文件夹<span lang="EN-US"><br />AuthName</span>指定当浏览器访问该目录时显示给用户的消息<span lang="EN-US"><br />AuthType </span>设置为<span lang="EN-US"> basic,</span>即基本<span lang="EN-US">HTTP</span>验证方式<span lang="EN-US"><br />AuthDBUserFile Berkeley</span>数据库的文件路径，它应该是<span lang="EN-US">web</span>文档根目录以外的地方 <span lang="EN-US">– </span>你不想让攻击者可以下载它吧<span lang="EN-US"><br />require </span>指明想要访问目录的用户必须存在于数据库中<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">上面这些的前提是用户可以被添加到数据库中，那么用户如何添加呢？请看下面这个函数：<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">function createUser($username, $password)</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">{</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$r1 = rand(1, strlen($chars) - 1);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$r2 = rand(1, strlen($chars) - 1);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$salt = substr($chars, $r1, 1) . substr($chars, $r2, 1);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$saltedPassword = crypt($password, $salt);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$resource = dba_open("</span><span lang="EN-US"><a href="http://www./www/basicAuth/api.example.com/passwords.dat" target="_top"><span style="font-size: 12pt; font-family: 宋体;">/www/basicAuth/api.example.com/passwords.dat</span></a></span><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">", "c", "db4");</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>if (dba_insert($username, $saltedPassword, $resource))</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>{</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>dba_close($resource);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>return true;</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>}else</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>{</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>dba_close($resource);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>return false;</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>}</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">}</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">该函数最重要的部分是用<span lang="EN-US">dba_open()</span>函数打开数据库（第二个参数“<span lang="EN-US">c”</span>指定如果文件不存在则创建他，<span lang="EN-US"> “db4”</span>是数据库类型）<span lang="EN-US">,</span>插入用户名和密码，然后关闭数据库连接。<span lang="EN-US"><o:p></o:p></span></span></p>
<table class="MsoNormalTable" style="" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr style="">
<td style="padding: 0cm;" valign="top"><a name="653"></a><a name="IDX-291"></a></td>
<td style="padding: 0cm; width: 49.35pt;" valign="top" width="82">
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">注意<span lang="EN-US">&nbsp;<o:p></o:p></span></span></p>
</td>
<td style="padding: 0cm; width: 365.65pt;" valign="top" width="609">
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">随机生成的<span lang="EN-US">salt</span>会随同密码发送到<span lang="EN-US">crypt</span>函数得到一个加密的密码从而可以提高字典攻击的难度。密码仍然可以被字典攻破，因为<span lang="EN-US">crypt</span>函数会把<span lang="EN-US">salt</span>添加到加密后的密码前面。<span lang="EN-US"><o:p></o:p></span></span></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">下面这个函数是删除用户<span lang="EN-US">:<o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">function deleteUser($user)</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">{</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$resource = dba_open("</span><span lang="EN-US"><a href="http://www./www/basicAuth/api.example.com/passwords.dat" target="_top"><span style="font-size: 12pt; font-family: 宋体;">/www/basicAuth/api.example.com/passwords.dat</span></a></span><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">", "c", "db4");</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>dba_delete($user, $resource);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>dba_close($resource);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">}</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">最后，你应该想要通过<span lang="EN-US">API</span>脚本访问用户信息：<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">$username = $_SERVER['PHP_AUTH_USER'];</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">$password = $_SERVER['PHP_AUTH_PW'];</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">这两个变量都存储与<span lang="EN-US">$_SERVER</span>这个全局数组里，<span lang="EN-US">password</span>是明文存储的，需要记住，用户这时已经通过了验证，因此这些信息只是用来存放基本数据罢了。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="654"></a><a name="ch12lev4sec2"></a><b><span style="font-size: 10pt; font-family: 宋体;">客户端代码<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">要访问<span lang="EN-US">API</span>，客户端程序需要发送一个包含了用户名和密码（<span lang="EN-US">Base64</span>加密过的）的<span lang="EN-US">HTTP</span>头。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">$authorization = base64_encode("username:password");</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">首先用户名和密码必须要用内置函数进行编码，“<span lang="EN-US">username:password</span>”则是<span lang="EN-US">HTTP </span>规范制定的格式。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">fputs($fp, "Authorization: Basic $authorization\r\n");</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">在<span lang="EN-US">socket</span>连接过程中，验证头始终都和<span lang="EN-US">HTTP</span>头部一起发送。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="655"></a><a name="ch12lev3sec3"></a><b><span style="font-size: 12pt; font-family: 宋体;">基于消息的验证<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">客户端验证信息也可以和一般的消息一起发送。因为增加一个验证信息对客户端代码来说并不是多大的负担。请记住，即便使用了<span lang="EN-US">SSL</span>，<span lang="EN-US">URL</span>仍然是以明文传输的，也就是说如果验证信息是通过<span lang="EN-US">URL</span>传递的（<span lang="EN-US">REST</span>请求），那么它对传输途中的任何人都是可见的。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">优点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">处理简单 <span lang="EN-US">– </span>每次处理都进行验证，如果一个普通页面。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">容易编码 <span lang="EN-US">– </span>程序员只需要增加一个额外的参数（验证信息）<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">方便跟踪 <span lang="EN-US">– </span>可以容易地配置统计某一段时间里有多少次调用，根据情况进行限流。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="656"></a><a name="IDX-292"></a><span style="font-size: 12pt; font-family: 宋体;">缺点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">验证信息是明文 <span lang="EN-US">–     REST APIs</span>会将验证信息以明文发送无论是否使用了安全的接入点。不安全的接入点也会把验证信息以明文格式发送，无论是<span lang="EN-US">REST</span>还是<span lang="EN-US">SOAP</span>。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">没有加密 <span lang="EN-US">– </span>所有请求和响应都是对可见的。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">基于消息的验证和<span lang="EN-US">HTTP</span>验证很相似，最主要的不同是由谁来处理验证过程，<span lang="EN-US">HTTP</span>是通过服务器，而基于消息的验证则是通过<span lang="EN-US">API</span>本身。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="657"></a><a name="ch12lev4sec3"></a><b><span style="font-size: 10pt; font-family: 宋体;">服务器端代码<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">切记验证信息应该和站内的其他验证信息分开。下面是一个基本的验证函数。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">function checkUser($username, $password)</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">{</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$query = "SELECT `user_level` FROM `users` WHERE `username` = ‘$username' AND</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>`password` = '$password'";</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>$results = getAssoc($query, 1);</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US"><span style="">&nbsp; </span>return $results[‘level'];</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">}</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="658"></a><a name="ch12lev4sec4"></a><b><span style="font-size: 10pt; font-family: 宋体;">客户端代码<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">取决于服务器端使用的是<span lang="EN-US">SOAP</span>还是<span lang="EN-US">REST</span>，这部分在后面的“<span lang="EN-US">REST</span>？还是<span lang="EN-US">SOAP</span>”中有讨论。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="659"></a><a name="ch12lev3sec4"></a><b><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">SSL </span></b><b><span style="font-size: 12pt; font-family: 宋体;">接入端<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">配置<span lang="EN-US">web</span>服务器支持<span lang="EN-US">SSL</span>连接可以保护请求和响应内容，同时又不需要额外编码。服务器端证书认证只能用来确认服务器而不能用来识别验证客户端。所以仍然需要前面两种验证机制。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">优点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">加密 <span lang="EN-US">– </span>请求和响应内容都被加密，从而不会存在被监听的问题。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">服务器验证 <span lang="EN-US">– </span>客户端可以根据<span lang="EN-US">SSL</span>证书来确认服务端没有改变。使用签名机构的证书同样可以达到这样的目的。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">配置简单 <span lang="EN-US">– </span>没有额外编码，只需要配置<span lang="EN-US">web</span>服务器。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="660"></a><a name="IDX-293"></a><span style="font-size: 12pt; font-family: 宋体;">缺点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">增加了服务器负担 <span lang="EN-US">– </span>加密和解密的过程本身就需要占用较多的<span lang="EN-US">CPU</span>资源，每个请求都会需要一个额外的握手过程来建立安全套接字。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">没有客户端验证 <span lang="EN-US">– </span>使用了<span lang="EN-US">SSL</span>。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">增加了客户端负担 <span lang="EN-US">– </span>处理<span lang="EN-US">SSL</span>对客户端来说通常都会比较繁琐，可能需要安装相应的扩展包才能实现（在共享主机环境下可能会比较麻烦）。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">SSL</span><span style="font-size: 12pt; font-family: 宋体;">对任何<span lang="EN-US">API</span>都是很重要的安全机制。它提供了对请求和响应内容的保护，以及服务器的识别。并且很容易和<span lang="EN-US">HTTP</span>认证或基于消息的认证结合。但是也要根据特定情况决定是否使用<span lang="EN-US">SSL</span>，因为它毕竟会增加一些负担给服务器和客户端。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="661"></a><a name="ch12lev4sec5"></a><b><span style="font-size: 10pt; font-family: 宋体;">服务器端代码<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">不需要代码，只需要配置<span lang="EN-US">web</span>服务器。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="662"></a><a name="ch12lev4sec6"></a><b><span style="font-size: 10pt; font-family: 宋体;">客户端代码<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">要连接<span lang="EN-US">SSL</span>接入端，<span lang="EN-US">PHP</span>需要配置“<span lang="EN-US">--with-openssl</span>”选项。同时要看服务器是否支持<span lang="EN-US">SSL</span>，从<span lang="EN-US">phpinfo()</span>输出中看是否在<span lang="EN-US">Registerd PHP Streams</span>有“<span lang="EN-US">https</span>”。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="663"></a><a name="ch12lev3sec5"></a><b><span style="font-size: 12pt; font-family: 宋体;">客户端证书<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">API</span><span style="font-size: 12pt; font-family: 宋体;">服务器可以为每个客户端生成一个证书来建立安全的信息传输，然后这个证书会被用在验证过程，确认服务器和客户端身份。尽管这种方法提供了最高级别的安全，但它也是要求对服务器端和客户端最严格的：并非所有的工具（比如<span lang="EN-US">NuSOAP</span>）都支持客户端证书。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">优点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">身份确认<span lang="EN-US">- </span>服务器和客户端的身份都得到了确认。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">加密 <span lang="EN-US">– </span>请求和响应内容都被保护，不会被第三方监听。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">缺点<span lang="EN-US">:<o:p></o:p></span></span></p>
<ul type="disc">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">增加了处理 <span lang="EN-US">– </span>因为需要建立安全套件字，额外的工作不可避免。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">服务端额外负担 <span lang="EN-US">– </span>服务器需要为每一个客户端都生成证书，并且要确保这些<span lang="EN-US">API</span>必须要存放安全的地方，通过安全的传输通道。<span lang="EN-US"><o:p></o:p></span></span></li>
</ul>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="664"></a><a name="IDX-294"></a><span style="font-size: 12pt; font-family: 宋体;">客户端证书确保了客户端和服务端的身份，可以一定程度上保证<span lang="EN-US">API</span>的安全，但是它的代价也是很明显的<span lang="EN-US"> - </span>客户端和服务器端的<span lang="EN-US">CPU</span>的负担，并且无法使用一些方便的客户端工具与<span lang="EN-US">API</span>交互。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="665"></a><a name="ch12lev4sec7"></a><b><span style="font-size: 10pt; font-family: 宋体;">服务器端代码<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">设置客户端证书需要一定量的工作，你很难说服所有试图使用<span lang="EN-US">API</span>的客户去花钱申请自己的证书。你也可以提供授权给客户，但这样也有一些不安全的问题 <span lang="EN-US">– </span>你必须要像一个真正的授权机构一样小心。但这仍然是一个相对轻松的解决办法，接下来我们详细介绍一下：<span lang="EN-US"><o:p></o:p></span></span></p>
<ol start="1" type="1">
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">设置证书授权。最好是使用一个独立的服务器来保存<span lang="EN-US">CA</span>的私钥，而不是用<span lang="EN-US">web</span>服务器，理想情况下，这台服务器最好不要接入互联网，而只可以连接请求密钥的机器，因为<span lang="EN-US">API</span>需要不停请求它生成密钥。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">为你的用户生成密钥，同时使用安全的连接分发。如果使用不安全的方式去分发，比如<span lang="EN-US">HTTP</span>，甚至<span lang="EN-US">email</span>，那么还不如不生成。因为完全没有必要去生成。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">配置<span lang="EN-US">web</span>服务器只接受生成的证书，用户必须提供由你签名的证书。<span lang="EN-US"><o:p></o:p></span></span></li>
<li class="MsoNormal" style="text-align: left;"><span style="font-size: 12pt; font-family: 宋体;">配置服务器使用<span lang="EN-US">SSL</span>认证。<span lang="EN-US"><o:p></o:p></span></span></li>
</ol>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="666"></a><a name="ch12lev3sec6"></a><b><span style="font-size: 12pt; font-family: 宋体;">建立你的认证（<span lang="EN-US">CA</span>）<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">OpenSSL</span><span style="font-size: 12pt; font-family: 宋体;">可以很好的完成这项工作，它包含两个很重要的脚本，<span lang="EN-US">CA.pl</span>和<span lang="EN-US">CA.sh</span>，可以自动完成这个过程。其他类似<span lang="EN-US">OpenCA</span>或者<span lang="EN-US">TinyCA</span>提供了界面更友好的方案。 考虑到你只需要做一次，那么太过友好的界面并不是很必要。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">首先需要修改<span lang="EN-US">CA</span>脚本，其中有一行代码：<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">$DAYS="-days 365"<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">定义了证书的有效期为一年以内（<span lang="EN-US">365</span>天），如果觉得太短，可以设置一个大一点的值，比如<span lang="EN-US">10</span>年。<span lang="EN-US">.<o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin-left: 6pt; text-align: left; text-indent: -6pt;" align="left"><span style="font-size: 12pt; font-family: 宋体;">其次，运行脚本时需要回答有关于公司的问题，<span lang="EN-US"> common name</span>这一项很重要<span lang="EN-US">- </span>它应该被配置为<span lang="EN-US">API</span>的主机名，记得使用一个健壮的密码。脚本执行时会生成一个<span lang="EN-US">demoCA</span>的文件夹，里面放置了所有生成好的文件。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">最后，生成服务器端证书。分两步，第一步，生成认证签名请求（<span lang="EN-US">Certificate Signing Request, CSR</span>）；第二部，使用<span lang="EN-US">CA</span>对<span lang="EN-US">CSR</span>进行签名。下面是用<span lang="EN-US">openssl</span>生成<span lang="EN-US">CSR</span>的命令：<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">openssl req -new –key server.key –out server.csr</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="667"></a><a name="IDX-295"></a><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">openSSL</span><span style="font-size: 12pt; font-family: 宋体;">在生成密钥之前会问一系列问题，这些需要和你创建<span lang="EN-US">CA</span>时的信息匹配，以免增加不必要的额外配置。要为生成的<span lang="EN-US">CSR</span>签名，首先需要把<span lang="EN-US">CSR</span>文件（<span lang="EN-US">server.csr</span>）重命名为<span lang="EN-US">newreq.pem</span>，然后使用下面这条命令：<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">CA.sh –signreq</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">它会为请求签名，最后必须要配置<span lang="EN-US">Apache</span>服务器使用证书，需要修改虚拟主机的<span lang="EN-US">httpd.conf</span>文件，增加如下信息：<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLEngine On</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLCertificateFile /etc/http/conf/ssl/server.crt</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLCertificateKeyFile /etc/http/conf/ssl/server.key</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLProtocol All –SSLv2</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLCipherSuite ALL:!EXP:!NULL:!ADH:!LOW</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">前三行用来打开<span lang="EN-US">SSL</span>引擎、设置证书路径和服务器私钥路径。最后两行用来阻止<span lang="EN-US">SSL</span>使用不安全的协议。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">第四，生成客户端证书：<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">CA.sh –newreq</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">CA.sh –signreq</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">记得通过安全的渠道分发给用户。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">第五，配置<span lang="EN-US">web</span>服务器要求客户在试图建立连接时提供证书，同时确保证书是由你签名和创建的。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLCACertificateFile /etc/http/conf/ssl/demoCA.crt</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLCARevocationFile /etc/http/conf/ssl/demoCA.crl</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLVerifyClient require</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="background: rgb(217, 217, 217) none repeat scroll 0% 0%; font-size: 12pt; font-family: 宋体; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;" lang="EN-US">SSLVerifyDepth</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">SSLCACertificateFile </span><span style="font-size: 12pt; font-family: 宋体;">要指向你放置<span lang="EN-US">CA</span>证书文件的位置，<span lang="EN-US"> SSLRevocationFile </span>要指向<span lang="EN-US">.crl</span>文件（该文件是和<span lang="EN-US">*.crt</span>文件同时生成的），没有这个文件，你就无法取消非法用户（或者不在使用<span lang="EN-US">API</span>的用户）。<span lang="EN-US">SSLVerifyClient </span>指明所有用户必须提供证书，否则将拒绝连接。最后，<span lang="EN-US"> SSLVerifyDepth 1 </span>指定所有客户端证书必须是由你的<span lang="EN-US">CA</span>直接生成的，这避免了其他用户创建合法的客户端证书。最后要重启<span lang="EN-US">Apache</span>来使这些配置生效。<span lang="EN-US"><o:p></o:p></span></span></p>
<table class="MsoNormalTable" style="" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr style="">
<td style="padding: 0cm;" valign="top"></td>
<td style="padding: 0cm; width: 35.15pt;" valign="top" width="59">
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">注意<span lang="EN-US">&nbsp;<o:p></o:p></span></span></p>
</td>
<td style="padding: 0cm; width: 379.85pt;" valign="top" width="633">
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">建议阅读<span lang="EN-US">Ivan Ristic</span>的《<span lang="EN-US">Apache Security</span>》了解更多的关于<span lang="EN-US">SSL</span>和<span lang="EN-US">Apache</span>相关的安全事宜。<span lang="EN-US"><o:p></o:p></span></span></p>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="text-align: left;" align="left"><a name="668"></a><a name="ch12lev4sec8"></a><b><span style="font-size: 10pt; font-family: 宋体;">客户端代码<span lang="EN-US"><o:p></o:p></span></span></b></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">要连接有安全的接入端，<span lang="EN-US">PHP</span>需要配置“<span lang="EN-US">--with-openssl” </span>选项<span lang="EN-US">,</span>同时要确定<span lang="EN-US">phpinfo()</span>的输出中有<span lang="EN-US">SSL</span>支持（<span lang="EN-US">Registered PHP Stream</span>列表），并且在<span lang="EN-US">Registered Stream Socket Transports </span>中也存在<span lang="EN-US">SSL</span>项。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;">因为必须要提供客户端证书，所以还要使用<span lang="EN-US">cURL</span>库。它适合用来调用<span lang="EN-US">SOAP</span>和<span lang="EN-US">REST API</span>，处理请求和响应都很类似：<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">function callAPI($endpoint, $requestBody)<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">{<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>$ch = curl_init();<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>curl_setopt($ch, CURLOPT_URL, $endpoint);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>curl_setopt($ch, CURLOPT_SSLCERT, "../certs/cert_key_pem-1.txt");<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>curl_setopt($ch, CURLOPT_POST, TRUE);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>ob_start();<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>curl_exec($ch);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>$response = ob_get_clean();<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp; </span>if (curl_error($ch))<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;</span>{<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;&nbsp; </span>file_put_contents("/tmp/curl_error_log.txt", curl_errno($ch) . ": ".<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>curl_error($ch), "a+");<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;&nbsp; </span>curl_close($ch);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;&nbsp; </span>return null;<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;</span>}else<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;</span>{<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>curl_close($ch);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;&nbsp;&nbsp; </span>return $response;<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US"><span style="">&nbsp;</span>}<o:p></o:p></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">}<o:p></o:p></span></p>
<p>  <span style="font-size: 12pt; font-family: 宋体;">这个函数使用客户端证书来建立连接，然后使用输出缓冲来获取响应内容（<span lang="EN-US">cURL</span>把输出直接发送给浏览器）。如果出现错误，响应出错信息会记录到文件；如果成功，响应结果会返回给调用函数。客户端证书切记要存放到安全的地方（<span lang="EN-US">web</span>文档根目录之外的位置）。</span></p>
<div class="zemanta-pixie"><img class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=64c8497f-7024-8dc7-b4c9-56eeca99948f" /></div>

	Tags: <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/openapi" title="openAPI" rel="tag">openAPI</a>, <a href="http://zhangv.com/archives/tag/rest" title="REST" rel="tag">REST</a>, <a href="http://zhangv.com/archives/tag/security" title="security" rel="tag">security</a>, <a href="http://zhangv.com/archives/tag/soap" title="SOAP" rel="tag">SOAP</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/1233/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ChromeOS是什么[翻译]</title>
		<link>http://zhangv.com/archives/1167</link>
		<comments>http://zhangv.com/archives/1167#comments</comments>
		<pubDate>Tue, 28 Jul 2009 02:08:55 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[ChromeOS]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[google]]></category>

		<guid isPermaLink="false">http://zhangv.com/archives/1167</guid>
		<description><![CDATA[原文：http://www.tech-no-media.com/2009/07/what-chromeos-is-not.html
很多人都对ChromeOS兴奋不已，很明显有些博客言过其实。也许是该总结一下到底google的新OS是（不是）什么了。
ChromeOS是：1.是linux：如果你认为Moblin(REF)是linux内核，clutter window manager也是linux的话。那么ChromeOS以及他还没有命名的轻量级窗口管理器也是linux。如同其他linux版本一样，ChromeOS也会开源，我们可能看到其他基于ChromeOS的版本 - 正如Ubuntu基于Debian一样。
2.是为上网本设计的操作系统：有一件事可以确定，ChromeOS会根据上网本的使用模式而专门优化，这和第一台EEE PC上的Xandros OS或 gOS类似：本地预装一部分应用程序，其他应用则基于云上。最主要的不同在于：google Gears使得云应用变得更易用，用户体验更好。如果你看一下google ChromeOS的合作伙伴，你会注意到他们大多在上网本市场有着很好的表现。
3.是基于ARM的：再看一眼合作伙伴，其中有Qualcomm,Freescale和德州电器，没有Intel！这三家是ARM芯片制造商同时对ChromeOS可以很好的运行在基于ARM的芯片上有很大的兴趣。对x86的兼容性会帮助ChromeOS占有更多的市场，但是大多数预装ChromeOS的机器会是基于ARM的。
4.会在货架上出售：对，ChromeOS的目标就是帮助出售便宜的上网电脑（用户只有上网机会为google创造价值）。在摆放时应避免和PC放到一起，造成消费者的混淆。
5.对linux来说是件好事：linux最大的问题是他的市场份额。因为linux只能代表2%的市场，很多软件，游戏和硬件商会忽略它，因为市场实在是太小了，不愿意将产品或者驱动移植到linux上。作为平衡，linux社区起到很大的作用，很多驱动，应用软件是由程序员自己开发的。但有一个问题，很多流行的游戏是由游戏工作室设计的，驱动应该是在硬件发布之前而不是之后开发的。如果基于linux的平台 - ChromeOS能够得到更多的市场份额，对整个linux社区都是一件好事 - 可以获得更好的商用软件供应商和硬件厂商的支持。
ChromeOS不是：1.并不完全依靠“云”：即便google没有使用Gnome或者KDE，她仍然可能会移植大多数的linux应用程序到ChromeOS，那么最终将有一整套完整的应用生态环境出现。尽管可能需要等上几年。因为Google gears的支持，类似google doc这样的web应用可以在离线状态下运行，所以本地应用程序可能是不需要的。
2.不是微软杀手：尽管为ChromeOS编写本地应用程序是可能的，但是ChromeOS最主要的目标是web接入。这意味着一开始可能只有很少的商用软件支持。因此，大多数人还是想要Windows作为他们的PC平台。ChromeOS可能只能在上网本制造商方面威胁到微软，但微软并没有在这方面赚钱，所以也就不大可能会引起大的对抗。
3.还没有准备好：google预期第一台装备ChromeOS的设备在2010年下半年诞生，尽管第一个beta版已经available。当ChromeOS上市的时候，Windows7和其他诸如Moblin和Jolicloud的linux操作系统将和它同台竞争。


	Tags: ChromeOS, 翻译, google
]]></description>
			<content:encoded><![CDATA[<p>原文：http://www.tech-no-media.com/2009/07/what-chromeos-is-not.html</p>
<p>很多人都对ChromeOS兴奋不已，很明显有些博客言过其实。也许是该总结一下到底google的新OS是（不是）什么了。</p>
<p>ChromeOS<b>是</b>：<br />1.是linux：如果你认为Moblin(REF)是linux内核，clutter window manager也是linux的话。那么ChromeOS以及他还没有命名的轻量级窗口管理器也是linux。如同其他linux版本一样，ChromeOS也会开源，我们可能看到其他基于ChromeOS的版本 - 正如Ubuntu基于Debian一样。</p>
<p>2.是为上网本设计的操作系统：有一件事可以确定，ChromeOS会根据上网本的使用模式而专门优化，这和第一台EEE PC上的Xandros OS或 gOS类似：本地预装一部分应用程序，其他应用则基于云上。最主要的不同在于：google Gears使得云应用变得更易用，用户体验更好。如果你看一下<a target="_blank" href="http://www.techcrunch.com/2009/07/08/chrome-partners-acer-adobe-asus-freescale-hewlett-packard-lenovo-qualcomm-texas-instruments/">google ChromeOS的合作伙伴</a>，你会注意到他们大多在上网本市场有着很好的表现。</p>
<p>3.是基于ARM的：再看一眼合作伙伴，其中有Qualcomm,Freescale和德州电器，没有Intel！这三家是ARM芯片制造商同时对ChromeOS可以很好的运行在基于ARM的芯片上有很大的兴趣。对x86的兼容性会帮助ChromeOS占有更多的市场，但是大多数预装ChromeOS的机器会是基于ARM的。</p>
<p>4.会在货架上出售：对，ChromeOS的目标就是帮助出售便宜的上网电脑（用户只有上网机会为google创造价值）。在摆放时应避免和PC放到一起，造成消费者的混淆。</p>
<p>5.对linux来说是件好事：linux最大的问题是他的市场份额。因为linux只能代表2%的市场，很多软件，游戏和硬件商会忽略它，因为市场实在是太小了，不愿意将产品或者驱动移植到linux上。作为平衡，linux社区起到很大的作用，很多驱动，应用软件是由程序员自己开发的。但有一个问题，很多流行的游戏是由游戏工作室设计的，驱动应该是在硬件发布之前而不是之后开发的。如果基于linux的平台 - ChromeOS能够得到更多的市场份额，对整个linux社区都是一件好事 - 可以获得更好的商用软件供应商和硬件厂商的支持。</p>
<p>ChromeOS<b>不是</b>：<br />1.并不完全依靠“云”：即便google没有使用Gnome或者KDE，她仍然可能会移植大多数的linux应用程序到ChromeOS，那么最终将有一整套完整的应用生态环境出现。尽管可能需要等上几年。因为Google gears的支持，类似google doc这样的web应用可以在离线状态下运行，所以本地应用程序可能是不需要的。</p>
<p>2.不是微软杀手：尽管为ChromeOS编写本地应用程序是可能的，但是ChromeOS最主要的目标是web接入。这意味着一开始可能只有很少的商用软件支持。因此，大多数人还是想要Windows作为他们的PC平台。ChromeOS可能只能在上网本制造商方面威胁到微软，但微软并没有在这方面赚钱，所以也就不大可能会引起大的对抗。</p>
<p>3.还没有准备好：google预期第一台装备ChromeOS的设备在2010年下半年诞生，尽管第一个beta版已经available。当ChromeOS上市的时候，Windows7和其他诸如Moblin和Jolicloud的linux操作系统将和它同台竞争。</p>
<div class="zemanta-pixie"><img class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=059720b8-18d9-8f4a-9ae1-a442a8e8f6b2" /></div>

	Tags: <a href="http://zhangv.com/archives/tag/chromeos" title="ChromeOS" rel="tag">ChromeOS</a>, <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/google" title="google" rel="tag">google</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/1167/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>REST API vs. SOAP API</title>
		<link>http://zhangv.com/archives/1067</link>
		<comments>http://zhangv.com/archives/1067#comments</comments>
		<pubDate>Sun, 07 Jun 2009 02:45:00 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[openAPI]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[SOAP]]></category>

		<guid isPermaLink="false">http://zhangv.com/archives/1067</guid>
		<description><![CDATA[译自“Professional Web APIs with PHP: eBay,
Google, PayPal, Amazon, FedEx, Plus Web Feeds”
REST API当处理REST请求时，因为信息是通过GET，所以，信息在传输过程中会进行URL编码(URL-encoded)；当需要进一步处理时，首先要进行解码（唯一例外是用户名和密码）。不同的请求类型应该使用不同的endpoints(URLs)；如果要以单独的脚本程序来处理所有的请求，你可以让所有的请求都指向同一个endpoint，或者配置web服务器来映射许多endpoints到同一个脚本。我建议用后一种方式；它符合规范同时允许你以后在不需要影响外部接口的情况下做修改。
允许程序员使用web接口来请求API - 在调试程序时将变得非常有用；程序员可以快速的判断问题源于请求本身还是代码。你可以提供给程序员的调试工具越多，你的网站也就越容易开发。
SOAP APIs当处理SOAP请求时，首先要检查请求是否符合WSDL指定的格式。如果你使用诸如NuSOAP的工具，他可以帮你做到这一点。事实上，大多数SOAP API使用一个框架来处理许多低级的工作。 SOAP API使用单一endpoint接收所有请求（作为一个通用规则，一些大的API会根据功能来拆分到不同的endpoint），因此，或者是你有一个很大的脚本文件，或者是在每个功能点都调用很多required()方法。
允许程序员在使用web接口时可以粘贴整个请求文档到一个表单，然后发送到你的服务器。从直接的经验来看，有这样一个工具对程序员调试程序时是非常有用的。提供脚本或者函数从而让程序员可以手动创建请求对那些没有使用SOAP框架的程序员是很有帮助的。

	Tags: 翻译, openAPI, REST, SOAP
]]></description>
			<content:encoded><![CDATA[<p>译自“<a border="0"><span class="b24-booktitle">Professional Web APIs with PHP: eBay,<br />
Google, PayPal, Amazon, FedEx, Plus Web Feeds”</span></a></p>
<p>REST API<br />当处理REST请求时，因为信息是通过GET，所以，信息在传输过程中会进行URL编码(URL-encoded)；当需要进一步处理时，首先要进行解码（唯一例外是用户名和密码）。不同的请求类型应该使用不同的endpoints(URLs)；如果要以单独的脚本程序来处理所有的请求，你可以让所有的请求都指向同一个endpoint，或者配置web服务器来映射许多endpoints到同一个脚本。我建议用后一种方式；它符合规范同时允许你以后在不需要影响外部接口的情况下做修改。</p>
<p>允许程序员使用web接口来请求API - 在调试程序时将变得非常有用；程序员可以快速的判断问题源于请求本身还是代码。你可以提供给程序员的调试工具越多，你的网站也就越容易开发。</p>
<p>SOAP APIs<br />当处理SOAP请求时，首先要检查请求是否符合WSDL指定的格式。如果你使用诸如NuSOAP的工具，他可以帮你做到这一点。事实上，大多数SOAP API使用一个框架来处理许多低级的工作。 SOAP API使用单一endpoint接收所有请求（作为一个通用规则，一些大的API会根据功能来拆分到不同的endpoint），因此，或者是你有一个很大的脚本文件，或者是在每个功能点都调用很多required()方法。</p>
<p>允许程序员在使用web接口时可以粘贴整个请求文档到一个表单，然后发送到你的服务器。从直接的经验来看，有这样一个工具对程序员调试程序时是非常有用的。提供脚本或者函数从而让程序员可以手动创建请求对那些没有使用SOAP框架的程序员是很有帮助的。</p>

	Tags: <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/openapi" title="openAPI" rel="tag">openAPI</a>, <a href="http://zhangv.com/archives/tag/rest" title="REST" rel="tag">REST</a>, <a href="http://zhangv.com/archives/tag/soap" title="SOAP" rel="tag">SOAP</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/1067/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>apache-derby连接jdbc连接url的解析</title>
		<link>http://zhangv.com/archives/475</link>
		<comments>http://zhangv.com/archives/475#comments</comments>
		<pubDate>Tue, 02 Sep 2008 03:14:18 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[derby]]></category>
		<category><![CDATA[数据库]]></category>

		<guid isPermaLink="false">http://zhangv.com/archives/475</guid>
		<description><![CDATA[来自http://db.apache.org/derby/docs/10.4/devguide/devguide-single.htm。我这里只是翻译一下，其实最关键要搞清楚的就是系统文件夹（通常是C:/databases)和类路径（从类路径开始或者从jar文件中开始查找）的区别。
jdbc:derby:db1
•打开系统文件夹中的db1
jdbc:derby:london/sales
•打开数据库lodon/sales，london位于系统文件夹下，sales是london的子目录
jdbc:derby:/reference/phrases/french
•打开数据库 /reference/phrases/french。 unix下，就是从根目录开始的路径。windows下则是C:\reference\phrases\french（如果当前驱动器是C.如果一个包含数据库的jar文件在用户的类路径下，则这个路径是jar文件内的路径。
jdbc:derby:a:/demo/sample
•打开驱动器A中的数据库，路径是\demo\sample
jdbc:derby:c:/databases/salesdb jdbc:derby:salesdb
•这两个连接到相同的数据库 - salesdb.在windows下derby默认的系统路径是C:\databases.
jdbc:derby:support/bugsdb;create=true
•在系统路径下创建一个新的数据库 - support/bugsdb。如果不存在，则自动产生相应的文件夹。
jdbc:derby:sample;shutdown=true
•关闭sample数据库。（如果没有启用验证，则不需要提供用户密码）
jdbc:derby:/myDB
•以只读方式连接myDB（位于类路径下）
jdbc:derby:classpath:/myDB
•同样以只读方式连接myDB数据库。使用classpath的原因是，路径下可能存在和数据库同名的文件夹。
jdbc:derby:jar:(C:/dbs.jar)products/boiledfood
•访问只读数据库boiledfood， 位于C:dbs.jar中的products文件夹。
jdbc:derby:directory:myDB
•访问myDB（位于系统文件夹）。使用directory是类路径下可能存在同名文件夹（myDB)

	Tags: 翻译, derby, 数据库
]]></description>
			<content:encoded><![CDATA[<p>来自http://db.apache.org/derby/docs/10.4/devguide/devguide-single.htm。我这里只是翻译一下，其实最关键要搞清楚的就是系统文件夹（通常是C:/databases)和类路径（从类路径开始或者从jar文件中开始查找）的区别。</p>
<p>jdbc:derby:db1<br />
•打开系统文件夹中的db1</p>
<p>jdbc:derby:london/sales<br />
•打开数据库lodon/sales，london位于系统文件夹下，sales是london的子目录</p>
<p>jdbc:derby:/reference/phrases/french</p>
<p>•打开数据库 /reference/phrases/french。 unix下，就是从根目录开始的路径。windows下则是C:\reference\phrases\french（如果当前驱动器是C.如果一个包含数据库的jar文件在用户的类路径下，则这个路径是jar文件内的路径。</p>
<p>jdbc:derby:a:/demo/sample<br />
•打开驱动器A中的数据库，路径是\demo\sample</p>
<p>jdbc:derby:c:/databases/salesdb jdbc:derby:salesdb<br />
•这两个连接到相同的数据库 - salesdb.在windows下derby默认的系统路径是C:\databases.</p>
<p>jdbc:derby:support/bugsdb;create=true<br />
•在系统路径下创建一个新的数据库 - support/bugsdb。如果不存在，则自动产生相应的文件夹。</p>
<p>jdbc:derby:sample;shutdown=true<br />
•关闭sample数据库。（如果没有启用验证，则不需要提供用户密码）</p>
<p>jdbc:derby:/myDB<br />
•以只读方式连接myDB（位于类路径下）</p>
<p>jdbc:derby:classpath:/myDB<br />
•同样以只读方式连接myDB数据库。使用classpath的原因是，路径下可能存在和数据库同名的文件夹。</p>
<p>jdbc:derby:jar:(C:/dbs.jar)products/boiledfood<br />
•访问只读数据库boiledfood， 位于C:dbs.jar中的products文件夹。</p>
<p>jdbc:derby:directory:myDB<br />
•访问myDB（位于系统文件夹）。使用directory是类路径下可能存在同名文件夹（myDB)</p>

	Tags: <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/derby" title="derby" rel="tag">derby</a>, <a href="http://zhangv.com/archives/tag/%e6%95%b0%e6%8d%ae%e5%ba%93" title="数据库" rel="tag">数据库</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/475/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OO设计原则</title>
		<link>http://zhangv.com/archives/439</link>
		<comments>http://zhangv.com/archives/439#comments</comments>
		<pubDate>Wed, 06 Aug 2008 09:15:08 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[OO]]></category>
		<category><![CDATA[SCEA]]></category>

		<guid isPermaLink="false">http://zhangv.com/?p=439</guid>
		<description><![CDATA[抖胆翻译一下scea study guide里的第一章的OO设计原则.纪录一下.
开闭原则
类应该被扩展,而不是被修改
Liskov替换原则
子类可以替换父类
依赖注入原则
依赖于抽象,而不是实现
接口分离原则
接口应该分开,避免单一通用的接口
合成重用原则
尽量用多态聚合代替继承
最少知识原则
操作知道尽可能少的当前类中的对象(自身,参数,类中的其他实例对象)
发布重用等效原则
细粒度的重用相当于细粒度的版本发布
包依赖:
共同关闭原则
一同变更的类应放在一起
公用重用原则
如果类不会一起被重用,就不应该放到一起.
非循环依赖原则
包之间不可以有循环依赖
依赖不变原则
依赖不应该经常变化
抽象不变原则
抽象包不应该经常变化

	Tags: 翻译, design, OO, SCEA
]]></description>
			<content:encoded><![CDATA[<p>抖胆翻译一下<a href="http://java.boot.by/scea5-guide/ch01.html">scea study guide</a>里的第一章的OO设计原则.纪录一下.</p>
<p>开闭原则<br />
类应该被扩展,而不是被修改</p>
<p>Liskov替换原则<br />
子类可以替换父类</p>
<p>依赖注入原则<br />
依赖于抽象,而不是实现</p>
<p>接口分离原则<br />
接口应该分开,避免单一通用的接口</p>
<p>合成重用原则<br />
尽量用多态聚合代替继承</p>
<p>最少知识原则<br />
操作知道尽可能少的当前类中的对象(自身,参数,类中的其他实例对象)</p>
<p>发布重用等效原则<br />
细粒度的重用相当于细粒度的版本发布</p>
<p>包依赖:</p>
<p>共同关闭原则<br />
一同变更的类应放在一起</p>
<p>公用重用原则<br />
如果类不会一起被重用,就不应该放到一起.</p>
<p>非循环依赖原则<br />
包之间不可以有循环依赖</p>
<p>依赖不变原则<br />
依赖不应该经常变化</p>
<p>抽象不变原则<br />
抽象包不应该经常变化</p>

	Tags: <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/design" title="design" rel="tag">design</a>, <a href="http://zhangv.com/archives/tag/oo" title="OO" rel="tag">OO</a>, <a href="http://zhangv.com/archives/tag/scea" title="SCEA" rel="tag">SCEA</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/439/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javablog » How MIDlet Signing is Killing J2ME</title>
		<link>http://zhangv.com/archives/155</link>
		<comments>http://zhangv.com/archives/155#comments</comments>
		<pubDate>Tue, 11 Mar 2008 12:54:32 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[j2me]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://218.22.170.60/zhangv/wordpress/?p=321</guid>
		<description><![CDATA[Javablog » How MIDlet Signing is Killing J2ME
TODO: 翻译

	Tags: 翻译, j2me, Java
]]></description>
			<content:encoded><![CDATA[<p><a href="http://javablog.co.uk/2007/08/09/how-midlet-signing-is-killing-j2me/">Javablog » How MIDlet Signing is Killing J2ME</a></p>
<p>TODO: 翻译</p>

	Tags: <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/j2me" title="j2me" rel="tag">j2me</a>, <a href="http://zhangv.com/archives/tag/java" title="Java" rel="tag">Java</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/155/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>实践的一小步-代码质量的一大步</title>
		<link>http://zhangv.com/archives/133</link>
		<comments>http://zhangv.com/archives/133#comments</comments>
		<pubDate>Mon, 18 Feb 2008 07:20:41 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[软件开发]]></category>

		<guid isPermaLink="false">http://218.22.170.60/zhangv/wordpress/?p=181</guid>
		<description><![CDATA[实践的一小步-代码质量的一大步
作者:Steven Hale December 14, 2007
翻译:ZhangV 2008-2-18
原文出自:DevX.com
原文链接:http://www.devx.com/Java/Article/36231/0/page/1
假设持续整合是你开发过程中很重要的一部,你也很想把代码覆盖检查并入你的自动构建过程.但是如何设定覆盖率目标呢?经验丰富的代码覆盖支持者会建议你75%,85%甚至100%.
通过对项目中的代码分析,我意识到需要设定比上述数据低得多的目标.我不想成为团队中的Cathcart上校(Josef Heller的小说&#60;&#60;第22条军规&#62;&#62;中的人物,因为每当部下已经达到当前的飞行任务次数时,他就会设定更高的任务次数,虽然Yossarian不断地完成飞行任务,但却似乎永远都无法完成这个总在变化的次数,小说中最后Yossarian开小差逃到瑞典-译者).
我选择增量改进的策略而不是专制的设定更高的目标.为了成功的执行这个策略,每次构建都必须达到比之前构建更高的覆盖率.通过每次一小步的提升,来最终提升代码质量.
以下介绍如何使用Cobertura和Apache Ant来实现这个增量改进.
单元测试,代码覆盖,持续整合
这三个概念已经被广泛的接受为最佳实践.事实上,大多数程序员知道他们必须要单元测试.如果你还不知道,让我来引用Google研发总监Peter Norvig的名言:
"如果你觉得不需要写单元测试,把所有原因写下来到一张纸上.仔细的揣摩这张纸.然后,扔掉这张纸开始写单元测试."
但是谁来测试测试人员呢? 也就是说,你怎么来确认你写了足够的测试呢?这些是非常宝贵的信息,因为那些没有被测试覆盖到的代码正是最耗费你经历的地方.一个解决办法是使用代码覆盖工具,它们会告诉你有被测试代码的百分比,然后加入一个代码覆盖检查到你的持续构建过程.如果你的覆盖检查不通过,那么构建也该被认定为失败.
在我的增量改进策略中,我选择Cobertura是因为她4个定义完整而简单的ant任务扩展.其中之一 cobertura-check,当代码覆盖率没有达到要求是会认定构建失败.例如下面这个例子,当覆盖率小于80%时,Ant会认为构建是失败的:
&#60;target name="coverage_check"&#62;
&#60;cobertura-check totallinerate="80"/&#62;
&#60;/target name="coverage_check"&#62;
但是,你可以使用之前的覆盖率来作为当前检查的标准.通过几个Cobertura的任务以及两个核心的ant任务,你就可以达到这个目标.而不需要担心是否应该考量 代码行率(line rate),分支率(branch rate)或者其他的覆盖数据.你的目标是改进,而不是一个绝对的硬性指标.
创建一个XML格式的代码覆盖报表
创建好ant任务后,你可以加入增量覆盖率检查到你的构建脚本中,第一步是用cobertura-report任务创建一个覆盖率报表:
&#60;cobertura-report format="xml"/&#62;
下面是一个生成的报表:
&#60;?xml version="1.0"?&#62;
&#60;!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-02.dtd"&#62;
&#60;coverage line-rate="0.43612334801762115" branch-rate="0.48344370860927155" version="1.8" timestamp="1181043899853"&#62;
&#60;sources&#62;
&#60;source&#62;./src/java&#60;/source&#62;
&#60;/sources&#62;
&#60;packages&#62;
...
&#60;/packages&#62;
&#60;/coverage&#62;
确保你把这个文件保存安全的地方(或者放到你的版本控制系统),因为之后你会用到他们.
从报表中得到覆盖率数据
一开始你可能会用Ant的XmlProperty任务来直接获取代码行率(line rate).但是这种做法有几个问题:
1.Cobertura的行率(line-rate)是十进制小鼠,但是cobertura-check是用整数形式的百分率
2.在一个实际的项目里,coverage.xml可能会很大,使用XmlProperty可能会造成内存不足的错误
我建议使用Ant的XSLT任务来获取你所需要的数据
&#60;xslt in="coverage.xml" out="build/coverage.properties" style="src/xsl/coverage.xsl" /&#62;
这个简单的xsl模板生成仅仅包含你所需要的数据的属性文件:
&#60;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0"&#62;
&#60;xsl:output method="text" omit-xml-declaration="yes"/&#62;
&#60;xsl:template match="coverage"&#62;
total.line-rate=
&#60;xsl:value-of select="floor(@line-rate*100)"/&#62;
&#60;/xsl:template&#62;
&#60;/xsl:stylesheet&#62;
注意方法:floor(@line-rate*100), 会把行率转成一个整数,生成的coverage.properties文件只有一行:
total.line-rate=44
这个属性文件仅仅是一个临时的文件,构建之后你可以把它清理掉.
使用Ant的property任务读入这个属性文件中唯一的值total.line-rate:
&#60;property file="build/coverage.properties" /&#62;
然后你可以把之前的"80"替换为新的Ant属性值:
&#60;cobertura-check totallinerate="${total.line-rate}"/&#62;
完整的例子
最终的build.xml应该是这样(其他的任务省略掉):
&#60;target name="coverage_check" depends="check_against_previous_rate"&#62;
&#60;antcall target="coverage_report"/&#62;
&#60;/target&#62;
&#60;target name="coverage_report"&#62;
&#60;cobertura-report format="xml" destdir="." /&#62;
&#60;/target&#62;
&#60;target name="check_against_previous_rate" depends="coverage_xml_to_properties"&#62;
&#60;property file="build/coverage.properties" /&#62;
&#60;cobertura-check totallinerate="${coverage.line-rate}" /&#62;
&#60;/target&#62;
&#60;target name="coverage_xml_to_properties"&#62;
&#60;xslt [...]]]></description>
			<content:encoded><![CDATA[<p>实践的一小步-代码质量的一大步<br />
作者:Steven Hale December 14, 2007<br />
翻译:ZhangV 2008-2-18<br />
原文出自:DevX.com<br />
原文链接:http://www.devx.com/Java/Article/36231/0/page/1</p>
<p>假设持续整合是你开发过程中很重要的一部,你也很想把代码覆盖检查并入你的自动构建过程.但是如何设定覆盖率目标呢?经验丰富的代码覆盖支持者会建议你75%,85%甚至100%.</p>
<p>通过对项目中的代码分析,我意识到需要设定比上述数据低得多的目标.我不想成为团队中的Cathcart上校(Josef Heller的小说&lt;&lt;第22条军规&gt;&gt;中的人物,因为每当部下已经达到当前的飞行任务次数时,他就会设定更高的任务次数,虽然Yossarian不断地完成飞行任务,但却似乎永远都无法完成这个总在变化的次数,小说中最后Yossarian开小差逃到瑞典-译者).</p>
<p>我选择增量改进的策略而不是专制的设定更高的目标.为了成功的执行这个策略,每次构建都必须达到比之前构建更高的覆盖率.通过每次一小步的提升,来最终提升代码质量.</p>
<p>以下介绍如何使用Cobertura和Apache Ant来实现这个增量改进.</p>
<p><strong>单元测试,代码覆盖,持续整合</strong><br />
这三个概念已经被广泛的接受为最佳实践.事实上,大多数程序员知道他们必须要单元测试.如果你还不知道,让我来引用Google研发总监Peter Norvig的名言:</p>
<p>"如果你觉得不需要写单元测试,把所有原因写下来到一张纸上.仔细的揣摩这张纸.然后,扔掉这张纸开始写单元测试."</p>
<p>但是谁来测试测试人员呢? 也就是说,你怎么来确认你写了足够的测试呢?这些是非常宝贵的信息,因为那些没有被测试覆盖到的代码正是最耗费你经历的地方.一个解决办法是使用代码覆盖工具,它们会告诉你有被测试代码的百分比,然后加入一个代码覆盖检查到你的持续构建过程.如果你的覆盖检查不通过,那么构建也该被认定为失败.</p>
<p>在我的增量改进策略中,我选择Cobertura是因为她4个定义完整而简单的ant任务扩展.其中之一 cobertura-check,当代码覆盖率没有达到要求是会认定构建失败.例如下面这个例子,当覆盖率小于80%时,Ant会认为构建是失败的:</p>
<p>&lt;target name="coverage_check"&gt;<br />
&lt;cobertura-check totallinerate="80"/&gt;<br />
&lt;/target name="coverage_check"&gt;</p>
<p>但是,你可以使用之前的覆盖率来作为当前检查的标准.通过几个Cobertura的任务以及两个核心的ant任务,你就可以达到这个目标.而不需要担心是否应该考量 代码行率(line rate),分支率(branch rate)或者其他的覆盖数据.你的目标是改进,而不是一个绝对的硬性指标.</p>
<p><strong>创建一个XML格式的代码覆盖报表</strong><br />
创建好ant任务后,你可以加入增量覆盖率检查到你的构建脚本中,第一步是用cobertura-report任务创建一个覆盖率报表:</p>
<p>&lt;cobertura-report format="xml"/&gt;</p>
<p>下面是一个生成的报表:</p>
<p>&lt;?xml version="1.0"?&gt;<br />
&lt;!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-02.dtd"&gt;</p>
<p>&lt;coverage line-rate="0.43612334801762115" branch-rate="0.48344370860927155" version="1.8" timestamp="1181043899853"&gt;<br />
&lt;sources&gt;<br />
&lt;source&gt;./src/java&lt;/source&gt;<br />
&lt;/sources&gt;<br />
&lt;packages&gt;<br />
...<br />
&lt;/packages&gt;<br />
&lt;/coverage&gt;</p>
<p>确保你把这个文件保存安全的地方(或者放到你的版本控制系统),因为之后你会用到他们.</p>
<p><strong>从报表中得到覆盖率数据</strong><br />
一开始你可能会用Ant的XmlProperty任务来直接获取代码行率(line rate).但是这种做法有几个问题:<br />
1.Cobertura的行率(line-rate)是十进制小鼠,但是cobertura-check是用整数形式的百分率<br />
2.在一个实际的项目里,coverage.xml可能会很大,使用XmlProperty可能会造成内存不足的错误</p>
<p>我建议使用Ant的XSLT任务来获取你所需要的数据</p>
<p>&lt;xslt in="coverage.xml" out="build/coverage.properties" style="src/xsl/coverage.xsl" /&gt;</p>
<p>这个简单的xsl模板生成仅仅包含你所需要的数据的属性文件:</p>
<p>&lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0"&gt;<br />
&lt;xsl:output method="text" omit-xml-declaration="yes"/&gt;<br />
&lt;xsl:template match="coverage"&gt;<br />
total.line-rate=<br />
&lt;xsl:value-of select="floor(@line-rate*100)"/&gt;<br />
&lt;/xsl:template&gt;<br />
&lt;/xsl:stylesheet&gt;</p>
<p>注意方法:floor(@line-rate*100), 会把行率转成一个整数,生成的coverage.properties文件只有一行:</p>
<p>total.line-rate=44</p>
<p>这个属性文件仅仅是一个临时的文件,构建之后你可以把它清理掉.</p>
<p>使用Ant的property任务读入这个属性文件中唯一的值total.line-rate:</p>
<p>&lt;property file="build/coverage.properties" /&gt;</p>
<p>然后你可以把之前的"80"替换为新的Ant属性值:</p>
<p>&lt;cobertura-check totallinerate="${total.line-rate}"/&gt;</p>
<p><strong>完整的例子</strong><br />
最终的build.xml应该是这样(其他的任务省略掉):</p>
<p>&lt;target name="coverage_check" depends="check_against_previous_rate"&gt;<br />
&lt;antcall target="coverage_report"/&gt;<br />
&lt;/target&gt;</p>
<p>&lt;target name="coverage_report"&gt;<br />
&lt;cobertura-report format="xml" destdir="." /&gt;<br />
&lt;/target&gt;</p>
<p>&lt;target name="check_against_previous_rate" depends="coverage_xml_to_properties"&gt;<br />
&lt;property file="build/coverage.properties" /&gt;<br />
&lt;cobertura-check totallinerate="${coverage.line-rate}" /&gt;<br />
&lt;/target&gt;</p>
<p>&lt;target name="coverage_xml_to_properties"&gt;<br />
&lt;xslt in="coverage.xml" out="build/coverage.properties" style="src/xsl/coverage.xsl" /&gt;<br />
&lt;/target&gt;</p>
<p>注意:新的覆盖报表只有在覆盖检查通过时才生成.(覆盖率必须要高于前一次的构建)</p>
<p>记得要先执行coverage_report,然后执行coverage_check.实际开发中,你应该加入另一个covertura-report任务来生成HTML的报表.</p>
<p><strong>跟踪改进率</strong><br />
一个附加的好处是你可以通过记录覆盖率数据到一个文件来跟踪改进率.通过echo人物:</p>
<p>&lt;target name="time"&gt;<br />
&lt;tstamp&gt;<br />
&lt;format property="date.time" pattern="yyyy-MM-dd HH:mm"/&gt;<br />
&lt;/tstamp&gt;<br />
&lt;/target&gt;</p>
<p>&lt;target name="log" depends="time"&gt;<br />
&lt;echo file="${history.txt}" append="true"&gt;<br />
${date.time};total.line-rate;${total.line-rate}<br />
&lt;/echo&gt;<br />
&lt;/target&gt;</p>
<p><strong>可量化的结果,看得见的改进</strong><br />
在使用了上述的措施后的一周后,我们的代码覆盖率提升了30%.可喜的是,那些之前不情愿写测试的程序员现在也很自豪地看到项目的覆盖率提升.</p>
<p>敏捷开发的民主精神在于,每一个团队成员都可以为整个团队提出目标 - 通过写单元测试. 没有专制的目标,没有cathcart上校.</p>
<p>你也可以更进一步.把这种增量式改进策略用到其他的地方.</p>
<p>作者Steven Hale,工作与瑞典的Omegapoint AB咨询公司.有超过20年的系统开发经验.</p>

	Tags: <a href="http://zhangv.com/archives/tag/agile" title="agile" rel="tag">agile</a>, <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/%e8%bd%af%e4%bb%b6%e5%bc%80%e5%8f%91" title="软件开发" rel="tag">软件开发</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/133/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>看板在行动(Kanban in Action)</title>
		<link>http://zhangv.com/archives/49</link>
		<comments>http://zhangv.com/archives/49#comments</comments>
		<pubDate>Mon, 26 Nov 2007 06:47:20 +0000</pubDate>
		<dc:creator>zhangv</dc:creator>
				<category><![CDATA[技术(Tech)]]></category>
		<category><![CDATA[看板]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[软件工程]]></category>

		<guid isPermaLink="false">http://218.22.170.60/zhangv/wordpress/?p=55</guid>
		<description><![CDATA[作者:DavidAnderson 原文
翻译:ZhangV 2007-11-26
之前，在讨论我在corbis所使用的软件工程管理方法时 ，我曾提到引入看板系统来维持项目运行。因为它的引入，我们现在每个月平均发布两个新的版本。然而，这些并没有使用传统的敏捷开发方法如两周迭代（two week iteration)或快速迭代（sprint)。而是用看板系统来管理变更请求（CR-Change Request）。当CR被完成时，它被设在准备发布状态，并在每周三被发布。
尽管我们让没有用Visual Studio的开发人员使用了outlook的teamlook客户端联入Team Foundation Server跟踪所有CR，但基本上的日常工作，我们都是使用白板作为看板来跟踪所有CR，把Post-It当作看板卡。
我们的支持过程是由一组常见的软件工程资源驱动的，没有一个专职的支持维护团队。通过设置看板，我们可以向管理层保证 - 我们正在履行我们的承诺，我们使用了一定的资源来进行支持活动，而不需要特别指出是谁在负责。
每天早会上所有团队成员会围绕看板来进行当天的工作安排，讨论进度和当前存在的问题。达伦戴维斯，作为项目经理，会主持会议，并分析每张卡片并与其他成员讨论。每张卡上写着CR的标题以及ID，及负责人的名字。每个负责人有责任根据当前CR的进行阶段移动相应CR的卡片。达伦利用每天的早会来保证Team Foundation Server上的数据和看板是同步的。该看板系统基本上是自我组织(self organizing)，但整个团队每天都会验证它的有效性。
一些关键概念。红星 - 这个任务已经严重超时的，超过28个工作日服务水平协议（ SLA），通过该系统。这使"迟到"的项目能够自我加速，不需直接管理干预。粉红色卡表示这个CR在Team Foundation Server里还是open的。这些粉红色卡包含了描述信息和在Team Foundation Server里的ID 。还有一些其他类型的卡片：黄色-客户提出（customer-valued)的CR;蓝色-客户提出（和要求）的BUG;绿色-IT维护项，如：的sql 2005的升级;橙色-新增（或额外）的BUG;粉红-issue。
看板限制卡片最多只能有20张，分为不同阶段，系统的分析，开发，测试，构建/合并，部署。此外，我们也允许有3个bug可以放在任何地方。这样可以有效地利用闲散资源。当人手不够的时候，我们会减少这个数量，或者干脆不要。此外，还有两个维护项，这让我们能解决固定分配一些资源到大大系统维护和升级，例如API版本升级，与平台的升级。 如net2.0或sql server 2005 。
看板赋予我们三个成功要素：

减少“进行中(work-in-progress)”， （讽刺的是，这些事情本身会限制工作的完成）
量入而出（如果有新的CR，首先看看板上有没有足够的空间）
确定优先顺序

我们每周和公司的技术总监开会讨论，决定任务的优先等级。他们从后台日志中拿出新的CR并考虑怎么把他们配置到看板上。这迫使他们思考哪些是最重要的事情。看板强迫他们给出优先等级。
看板还把我们从定时迭代的压迫（constraints of time-boxed iterations)中解放出来。尽管我们现在每两个星期发布一个新版本，大的任务可以在系统中最多可以存在60天。那些对于“一（两）周迭代”来说太大的任务同样可以放到看板里，而不需要特殊对待。
最后，看板解放了我们，我们不再把每个迭代都当作一个小型的项目而投入过多的管理成本它基本上是自行组织和管理，除非有特殊情况出现，如需要加快请求或因环境或系统的维修问题变更发布时间。
technorati的标签：敏捷，朱+安德森，精益生产，看板，软件+工程
顺便问一下customer-valued怎么翻译？
最后修改：2009-8-12

	Tags: 看板, 翻译, 软件工程
]]></description>
			<content:encoded><![CDATA[<p>作者:DavidAnderson<a href="http://www.agilemanagement.net/Articles/Weblog/KanbaninAction.html"> 原文</a><br />
翻译:ZhangV 2007-11-26</p>
<p>之前，在讨论我在corbis所使用的软件工程管理方法时 ，我曾提到引入看板系统来维持项目运行。因为它的引入，我们现在每个月平均发布两个新的版本。然而，这些并没有使用传统的敏捷开发方法如两周迭代（two week iteration)或快速迭代（sprint)。而是用看板系统来管理变更请求（CR-Change Request）。当CR被完成时，它被设在准备发布状态，并在每周三被发布。</p>
<p>尽管我们让没有用Visual Studio的开发人员使用了outlook的teamlook客户端联入Team Foundation Server跟踪所有CR，但基本上的日常工作，我们都是使用白板作为看板来跟踪所有CR，把Post-It当作看板卡。</p>
<p>我们的支持过程是由一组常见的软件工程资源驱动的，没有一个专职的支持维护团队。通过设置看板，我们可以向管理层保证 - 我们正在履行我们的承诺，我们使用了一定的资源来进行支持活动，而不需要特别指出是谁在负责。</p>
<p>每天早会上所有团队成员会围绕看板来进行当天的工作安排，讨论进度和当前存在的问题。达伦戴维斯，作为项目经理，会主持会议，并分析每张卡片并与其他成员讨论。每张卡上写着CR的标题以及ID，及负责人的名字。每个负责人有责任根据当前CR的进行阶段移动相应CR的卡片。达伦利用每天的早会来保证Team Foundation Server上的数据和看板是同步的。该看板系统基本上是自我组织(self organizing)，但整个团队每天都会验证它的有效性。</p>
<p>一些关键概念。红星 - 这个任务已经严重超时的，超过28个工作日服务水平协议（ SLA），通过该系统。这使"迟到"的项目能够自我加速，不需直接管理干预。粉红色卡表示这个CR在Team Foundation Server里还是open的。这些粉红色卡包含了描述信息和在Team Foundation Server里的ID 。还有一些其他类型的卡片：黄色-客户提出（customer-valued)的CR;蓝色-客户提出（和要求）的BUG;绿色-IT维护项，如：的sql 2005的升级;橙色-新增（或额外）的BUG;粉红-issue。</p>
<p>看板限制卡片最多只能有20张，分为不同阶段，系统的分析，开发，测试，构建/合并，部署。此外，我们也允许有3个bug可以放在任何地方。这样可以有效地利用闲散资源。当人手不够的时候，我们会减少这个数量，或者干脆不要。此外，还有两个维护项，这让我们能解决固定分配一些资源到大大系统维护和升级，例如API版本升级，与平台的升级。 如net2.0或sql server 2005 。</p>
<p>看板赋予我们三个成功要素：</p>
<ul>
<li>减少“进行中(work-in-progress)”， （讽刺的是，这些事情本身会限制工作的完成）</li>
<li>量入而出（如果有新的CR，首先看看板上有没有足够的空间）</li>
<li>确定优先顺序</li>
</ul>
<p>我们每周和公司的技术总监开会讨论，决定任务的优先等级。他们从后台日志中拿出新的CR并考虑怎么把他们配置到看板上。这迫使他们思考哪些是最重要的事情。看板强迫他们给出优先等级。</p>
<p>看板还把我们从定时迭代的压迫（constraints of time-boxed iterations)中解放出来。尽管我们现在每两个星期发布一个新版本，大的任务可以在系统中最多可以存在60天。那些对于“一（两）周迭代”来说太大的任务同样可以放到看板里，而不需要特殊对待。</p>
<p>最后，看板解放了我们，我们不再把每个迭代都当作一个小型的项目而投入过多的管理成本它基本上是自行组织和管理，除非有特殊情况出现，如需要加快请求或因环境或系统的维修问题变更发布时间。</p>
<p>technorati的标签：敏捷，朱+安德森，精益生产，看板，软件+工程</p>
<p>顺便问一下customer-valued怎么翻译？</p>
<p>最后修改：2009-8-12</p>

	Tags: <a href="http://zhangv.com/archives/tag/%e7%9c%8b%e6%9d%bf" title="看板" rel="tag">看板</a>, <a href="http://zhangv.com/archives/tag/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://zhangv.com/archives/tag/%e8%bd%af%e4%bb%b6%e5%b7%a5%e7%a8%8b" title="软件工程" rel="tag">软件工程</a><br />
]]></content:encoded>
			<wfw:commentRss>http://zhangv.com/archives/49/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

