<?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>idv2 &#187; web</title>
	<atom:link href="http://tech.idv2.com/category/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://tech.idv2.com</link>
	<description>关注Web开发技术，关注Internet。</description>
	<lastBuildDate>Tue, 27 Jul 2010 12:54:54 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>[CakePHP]如何关闭API页面的调试信息</title>
		<link>http://tech.idv2.com/2009/07/26/cakephp-close-debuginfo-in-api/</link>
		<comments>http://tech.idv2.com/2009/07/26/cakephp-close-debuginfo-in-api/#comments</comments>
		<pubDate>Sun, 26 Jul 2009 12:21:34 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[cakephp]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2009/07/26/cakephp-close-debuginfo-in-api/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>注：本文使用的CakePHP版本为 1.2.3.8166。</p>
<p>使用<a href="http://cakephp.org/">CakePHP</a>开发时，免不了要将调试级别设置为2，
这样页面上会显示出执行的SQL语句及结果，很方便。
但在做API页面时就比较麻烦。一般API页面的输出结果是XML或者JSON格式，
如果后面多了些调试信息，客户端就无法正确解析了。</p>
<p>解决方法很简单，只要在API的action函数中改写调试等级即可：</p>
<pre>function api_index() {
  ...
  Configure::write('debug', 0);
}</pre>
<p>不过，每个action都要写这么一行，太麻烦了。能不能想个办法，自动地关闭所有API页面的调试信息？</p>
<!-- end Pukiwiki generated code--><span id="more-710"></span><!-- begin Pukiwiki generated code--><p>可以仿照管理界面的方式。管理界面的URL为  /admin/posts/index，
这样就可以自动调用 PostsController的 admin_index() 函数。
类似地，我们可以把所有 API 的URL都写成 /api/posts/index，
让CakePHP自动调用 PostsController 的 api_index() 函数。
只需在 config/routes.php 中添加下面一行：</p>
<pre>Router::connect('/api/:controller/:action/*', array('prefix' =&gt; 'api', 'api' =&gt; true));</pre>
<p>简单说明一下：上述路径中的 :controller 和 :action 为系统默认的路径元素，
只需写在适当的位置，CakePHP即可识别出Controller和Action。
prefix选项指定action函数的前缀为API，这样系统就会调用 api_index()函数。
最后的 'api' =&gt; true 是个标志，加上以后，传给 action 的 $this-&gt;params 数组中
就会出现 'api' =&gt; true 这个值，稍后我们会用到它。</p>
<p>接下来新建 /api_controller.php 文件，如果已存在，就修改一下：</p>
<pre>&lt;?php
class AppController extends Controller {

  function beforeFilter() {
    // 如果是API请求，则关闭调试信息
    if (isset($this-&gt;params['api'])) {
      $this-&gt;layout = 'api';
      $debug = Configure::read('debug');
      if ($debug &gt; 0) {
        Configure::write('debug', 0);
      }
    }
  }
}
?&gt;</pre>
<p>使用beforeFilter()函数，在请求到达真正的action函数之前，判断是否为API请求，
如果是，就将页面布局设置为 'api'，再关闭调试信息。</p>
<p>当然，别忘了建立 /pages/layouts/api.ctp 文件，只需一行：</p>
<pre>&lt;?php echo $content_for_layout ?&gt;</pre>
<p>这样，以后访问API时只要写成 /api/controller/action 即可，系统会自动关闭调试信息，
并自动应用API的页面模板。</p>
<!-- end Pukiwiki generated code-->]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>注：本文使用的CakePHP版本为 1.2.3.8166。</p>
<p>使用<a href="http://cakephp.org/">CakePHP</a>开发时，免不了要将调试级别设置为2，
这样页面上会显示出执行的SQL语句及结果，很方便。
但在做API页面时就比较麻烦。一般API页面的输出结果是XML或者JSON格式，
如果后面多了些调试信息，客户端就无法正确解析了。</p>
<p>解决方法很简单，只要在API的action函数中改写调试等级即可：</p>
<pre>function api_index() {
  ...
  Configure::write('debug', 0);
}</pre>
<p>不过，每个action都要写这么一行，太麻烦了。能不能想个办法，自动地关闭所有API页面的调试信息？</p>
<!-- end Pukiwiki generated code--><span id="more-710"></span><!-- begin Pukiwiki generated code--><p>可以仿照管理界面的方式。管理界面的URL为  /admin/posts/index，
这样就可以自动调用 PostsController的 admin_index() 函数。
类似地，我们可以把所有 API 的URL都写成 /api/posts/index，
让CakePHP自动调用 PostsController 的 api_index() 函数。
只需在 config/routes.php 中添加下面一行：</p>
<pre>Router::connect('/api/:controller/:action/*', array('prefix' =&gt; 'api', 'api' =&gt; true));</pre>
<p>简单说明一下：上述路径中的 :controller 和 :action 为系统默认的路径元素，
只需写在适当的位置，CakePHP即可识别出Controller和Action。
prefix选项指定action函数的前缀为API，这样系统就会调用 api_index()函数。
最后的 'api' =&gt; true 是个标志，加上以后，传给 action 的 $this-&gt;params 数组中
就会出现 'api' =&gt; true 这个值，稍后我们会用到它。</p>
<p>接下来新建 /api_controller.php 文件，如果已存在，就修改一下：</p>
<pre>&lt;?php
class AppController extends Controller {

  function beforeFilter() {
    // 如果是API请求，则关闭调试信息
    if (isset($this-&gt;params['api'])) {
      $this-&gt;layout = 'api';
      $debug = Configure::read('debug');
      if ($debug &gt; 0) {
        Configure::write('debug', 0);
      }
    }
  }
}
?&gt;</pre>
<p>使用beforeFilter()函数，在请求到达真正的action函数之前，判断是否为API请求，
如果是，就将页面布局设置为 'api'，再关闭调试信息。</p>
<p>当然，别忘了建立 /pages/layouts/api.ctp 文件，只需一行：</p>
<pre>&lt;?php echo $content_for_layout ?&gt;</pre>
<p>这样，以后访问API时只要写成 /api/controller/action 即可，系统会自动关闭调试信息，
并自动应用API的页面模板。</p>
<!-- end Pukiwiki generated code-->]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2009/07/26/cakephp-close-debuginfo-in-api/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>使用Apache做负载均衡</title>
		<link>http://tech.idv2.com/2009/07/22/loadbalancer-with-apache/</link>
		<comments>http://tech.idv2.com/2009/07/22/loadbalancer-with-apache/#comments</comments>
		<pubDate>Wed, 22 Jul 2009 02:59:01 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[server]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2009/07/22/loadbalancer-with-apache/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>第一次看到这个标题时我也很惊讶，Apache居然还能做负载均衡？真是太强大了。
经过一番调查后发现的确可以，而且功能一点都不差。
这都归功于 mod_proxy 这个模块。
不愧是强大的Apache啊。</p>
<p>废话少说，下面就来解释一下负载均衡的设置方法。</p>
<!-- end Pukiwiki generated code--><span id="more-709"></span><!-- begin Pukiwiki generated code--><p>一般来说，负载均衡就是将客户端的请求分流给后端的各个真实服务器，
达到负载均衡的目的。还有一种方式是用两台服务器，一台作为主服务器(Master)，
另一台作为热备份(Hot Standby)，请求全部分给主服务器，在主服务器当机时，
立即切换到备份服务器，以提高系统的整体可靠性。</p>
<p><strong>负载均衡的设置</strong></p>
<p>Apache可以应对上面这两种需求。先来讨论一下如何做负载均衡。
首先需要启用Apache的几个模块：</p>
<pre>LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_http_module modules/mod_proxy_http.so</pre>
<p>mod_proxy提供代理服务器功能，mod_proxy_balancer提供负载均衡功能，
mod_proxy_http让代理服务器能支持HTTP协议。如果把mod_proxy_http换成
其他协议模块（如mod_proxy_ftp），或许能支持其他协议的负载均衡，
有兴趣的朋友可以自己尝试一下。</p>
<p>然后要添加以下配置：</p>
<pre>ProxyRequests Off
&lt;Proxy balancer://mycluster&gt;
    BalancerMember http://node-a.myserver.com:8080
    BalancerMember http://node-b.myserver.com:8080
&lt;/Proxy&gt;
ProxyPass / balancer://mycluster

# 警告：以下这段配置仅用于调试，绝不要添加到生产环境中！！！
&lt;Location /balancer-manager&gt;
    SetHandler balancer-manager
    Order Deny,Allow
    Deny from all
    Allow from localhost
&lt;/Location&gt; </pre>
<p>从上面的 ProxyRequests Off 这条可以看出，实际上负载均衡器就是一个反向代理，
只不过它的代理转发地址不是某台具体的服务器，而是一个 balancer:// 协议：</p>
<pre>ProxyPass / balancer://mycluster</pre>
<p>协议地址可以随便定义。然后，在&lt;Proxy&gt;段中设置该balancer协议的内容即可。
BalancerMember指令可以添加负载均衡组中的真实服务器地址。</p>
<p>下面那段&lt;Location /balancer-manager&gt;是用来监视负载均衡的工作情况的，
调试时可以加上（生产环境中禁止使用！），然后访问 <a href="http://localhost/balancer-manager/">http://localhost/balancer-manager/</a> 即可看到
负载均衡的工作状况。</p>
<p>OK，改完之后重启服务器，访问你的Apache所在服务器的地址，即可看到负载均衡的效果了。
打开 balancer-manager 的界面，可以看到请求是平均分配的。</p>
<p>如果不想平均分配怎么办？给 BalancerMember 加上 loadfactor 参数即可，取值范围为1-100。
比如你有三台服务器，负载分配比例为 7:2:1，只需这样设置：</p>
<pre>ProxyRequests Off
&lt;Proxy balancer://mycluster&gt;
    BalancerMember http://node-a.myserver.com:8080 loadfactor=7
    BalancerMember http://node-b.myserver.com:8080 loadfactor=2
    BalancerMember http://node-c.myserver.com:8080 loadfactor=1
&lt;/Proxy&gt;
ProxyPass / balancer://mycluster</pre>
<p>默认情况下，负载均衡会尽量让各个服务器接受的请求次数满足预设的比例。
如果要改变算法，可以使用 lbmethod 属性。如：</p>
<pre>ProxyRequests Off
&lt;Proxy balancer://mycluster&gt;
    BalancerMember http://node-a.myserver.com:8080 loadfactor=7
    BalancerMember http://node-b.myserver.com:8080 loadfactor=2
    BalancerMember http://node-c.myserver.com:8080 loadfactor=1
&lt;/Proxy&gt;
ProxyPass / balancer://mycluster
ProxySet lbmethod=bytraffic</pre>
<p>lbmethod可能的取值有：</p>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">lbmethod=byrequests</td><td class="style_td">按照请求次数均衡(默认)</td></tr><tr><td class="style_td">lbmethod=bytraffic</td><td class="style_td">按照流量均衡</td></tr><tr><td class="style_td">lbmethod=bybusyness</td><td class="style_td">按照繁忙程度均衡(总是分配给活跃请求数最少的服务器)</td></tr></tbody></table></div>
<p>各种算法的原理请参见<a href="http://httpd.apache.org/docs/2.2/en/mod/mod_proxy_balancer.html">Apache的文档</a>。</p>
<p><strong>热备份(Hot Standby)</strong></p>
<p>热备份的实现很简单，只需添加 status=+H 属性，就可以把某台服务器指定为备份服务器：</p>
<pre>ProxyRequests Off
&lt;Proxy balancer://mycluster&gt;
    BalancerMember http://node-a.myserver.com:8080
    BalancerMember http://node-b.myserver.com:8080 status=+H
&lt;/Proxy&gt;
ProxyPass / balancer://mycluster</pre>
<p>从 balancer-manager 界面中可以看到，请求总是流向 node-a ，一旦node-a挂掉，
Apache会检测到错误并把请求分流给 node-b。Apache会每隔几分钟检测一下 node-a 的状况，
如果node-a恢复，就继续使用node-a。</p>
<!-- end Pukiwiki generated code-->
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>第一次看到这个标题时我也很惊讶，Apache居然还能做负载均衡？真是太强大了。
经过一番调查后发现的确可以，而且功能一点都不差。
这都归功于 mod_proxy 这个模块。
不愧是强大的Apache啊。</p>
<p>废话少说，下面就来解释一下负载均衡的设置方法。</p>
<!-- end Pukiwiki generated code--><span id="more-709"></span><!-- begin Pukiwiki generated code--><p>一般来说，负载均衡就是将客户端的请求分流给后端的各个真实服务器，
达到负载均衡的目的。还有一种方式是用两台服务器，一台作为主服务器(Master)，
另一台作为热备份(Hot Standby)，请求全部分给主服务器，在主服务器当机时，
立即切换到备份服务器，以提高系统的整体可靠性。</p>
<p><strong>负载均衡的设置</strong></p>
<p>Apache可以应对上面这两种需求。先来讨论一下如何做负载均衡。
首先需要启用Apache的几个模块：</p>
<pre>LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_http_module modules/mod_proxy_http.so</pre>
<p>mod_proxy提供代理服务器功能，mod_proxy_balancer提供负载均衡功能，
mod_proxy_http让代理服务器能支持HTTP协议。如果把mod_proxy_http换成
其他协议模块（如mod_proxy_ftp），或许能支持其他协议的负载均衡，
有兴趣的朋友可以自己尝试一下。</p>
<p>然后要添加以下配置：</p>
<pre>ProxyRequests Off
&lt;Proxy balancer://mycluster&gt;
    BalancerMember http://node-a.myserver.com:8080
    BalancerMember http://node-b.myserver.com:8080
&lt;/Proxy&gt;
ProxyPass / balancer://mycluster

# 警告：以下这段配置仅用于调试，绝不要添加到生产环境中！！！
&lt;Location /balancer-manager&gt;
    SetHandler balancer-manager
    Order Deny,Allow
    Deny from all
    Allow from localhost
&lt;/Location&gt; </pre>
<p>从上面的 ProxyRequests Off 这条可以看出，实际上负载均衡器就是一个反向代理，
只不过它的代理转发地址不是某台具体的服务器，而是一个 balancer:// 协议：</p>
<pre>ProxyPass / balancer://mycluster</pre>
<p>协议地址可以随便定义。然后，在&lt;Proxy&gt;段中设置该balancer协议的内容即可。
BalancerMember指令可以添加负载均衡组中的真实服务器地址。</p>
<p>下面那段&lt;Location /balancer-manager&gt;是用来监视负载均衡的工作情况的，
调试时可以加上（生产环境中禁止使用！），然后访问 <a href="http://localhost/balancer-manager/">http://localhost/balancer-manager/</a> 即可看到
负载均衡的工作状况。</p>
<p>OK，改完之后重启服务器，访问你的Apache所在服务器的地址，即可看到负载均衡的效果了。
打开 balancer-manager 的界面，可以看到请求是平均分配的。</p>
<p>如果不想平均分配怎么办？给 BalancerMember 加上 loadfactor 参数即可，取值范围为1-100。
比如你有三台服务器，负载分配比例为 7:2:1，只需这样设置：</p>
<pre>ProxyRequests Off
&lt;Proxy balancer://mycluster&gt;
    BalancerMember http://node-a.myserver.com:8080 loadfactor=7
    BalancerMember http://node-b.myserver.com:8080 loadfactor=2
    BalancerMember http://node-c.myserver.com:8080 loadfactor=1
&lt;/Proxy&gt;
ProxyPass / balancer://mycluster</pre>
<p>默认情况下，负载均衡会尽量让各个服务器接受的请求次数满足预设的比例。
如果要改变算法，可以使用 lbmethod 属性。如：</p>
<pre>ProxyRequests Off
&lt;Proxy balancer://mycluster&gt;
    BalancerMember http://node-a.myserver.com:8080 loadfactor=7
    BalancerMember http://node-b.myserver.com:8080 loadfactor=2
    BalancerMember http://node-c.myserver.com:8080 loadfactor=1
&lt;/Proxy&gt;
ProxyPass / balancer://mycluster
ProxySet lbmethod=bytraffic</pre>
<p>lbmethod可能的取值有：</p>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">lbmethod=byrequests</td><td class="style_td">按照请求次数均衡(默认)</td></tr><tr><td class="style_td">lbmethod=bytraffic</td><td class="style_td">按照流量均衡</td></tr><tr><td class="style_td">lbmethod=bybusyness</td><td class="style_td">按照繁忙程度均衡(总是分配给活跃请求数最少的服务器)</td></tr></tbody></table></div>
<p>各种算法的原理请参见<a href="http://httpd.apache.org/docs/2.2/en/mod/mod_proxy_balancer.html">Apache的文档</a>。</p>
<p><strong>热备份(Hot Standby)</strong></p>
<p>热备份的实现很简单，只需添加 status=+H 属性，就可以把某台服务器指定为备份服务器：</p>
<pre>ProxyRequests Off
&lt;Proxy balancer://mycluster&gt;
    BalancerMember http://node-a.myserver.com:8080
    BalancerMember http://node-b.myserver.com:8080 status=+H
&lt;/Proxy&gt;
ProxyPass / balancer://mycluster</pre>
<p>从 balancer-manager 界面中可以看到，请求总是流向 node-a ，一旦node-a挂掉，
Apache会检测到错误并把请求分流给 node-b。Apache会每隔几分钟检测一下 node-a 的状况，
如果node-a恢复，就继续使用node-a。</p>
<!-- end Pukiwiki generated code-->
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2009/07/22/loadbalancer-with-apache/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>[Java]查看Tocmat的运行状态</title>
		<link>http://tech.idv2.com/2009/06/24/tomcat-status/</link>
		<comments>http://tech.idv2.com/2009/06/24/tomcat-status/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 01:43:16 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jsp]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2009/06/24/tomcat-status/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>熟悉J2EE开发的人应该对此不屑一顾吧，俺是Java新手，没办法……做个笔记先。
Tomcat 5.5下测试通过。</p>
<p>首先要添加管理员用户。打开 conf/tomcat-users.xml，在其中加入这样一行：</p>
<pre>&lt;user username=&quot;manager&quot; password=&quot;password&quot; roles=&quot;standard,manager&quot;/&gt;</pre>
<p>然后重启Tomcat。</p>
<p>之后访问以下地址：</p>
<pre>http://localhost:8080/manager/status</pre>
<p>输入刚才设置好的管理员用户名和密码，就能看到服务器状态的页面。
其中几个比较重要的数值：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>Max threads: 150           最大线程数</li>
<li>Min spare threads: 25      最小空闲线程数</li>
<li>Max spare threads: 75      最大空闲线程数</li>
<li>Current thread count: 25   当前线程数</li>
<li>Current thread busy: 2     当前繁忙线程数</li></ul>
<!-- end Pukiwiki generated code-->]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>熟悉J2EE开发的人应该对此不屑一顾吧，俺是Java新手，没办法……做个笔记先。
Tomcat 5.5下测试通过。</p>
<p>首先要添加管理员用户。打开 conf/tomcat-users.xml，在其中加入这样一行：</p>
<pre>&lt;user username=&quot;manager&quot; password=&quot;password&quot; roles=&quot;standard,manager&quot;/&gt;</pre>
<p>然后重启Tomcat。</p>
<p>之后访问以下地址：</p>
<pre>http://localhost:8080/manager/status</pre>
<p>输入刚才设置好的管理员用户名和密码，就能看到服务器状态的页面。
其中几个比较重要的数值：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>Max threads: 150           最大线程数</li>
<li>Min spare threads: 25      最小空闲线程数</li>
<li>Max spare threads: 75      最大空闲线程数</li>
<li>Current thread count: 25   当前线程数</li>
<li>Current thread busy: 2     当前繁忙线程数</li></ul>
<!-- end Pukiwiki generated code-->]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2009/06/24/tomcat-status/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[GreaseMonkey]如何hook已有函数</title>
		<link>http://tech.idv2.com/2009/03/16/hook-function-in-greasemonkey/</link>
		<comments>http://tech.idv2.com/2009/03/16/hook-function-in-greasemonkey/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 02:54:37 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[greasemonkey]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2009/03/16/hook-function-in-greasemonkey/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>GreaseMonkey这个插件大家都早已熟悉了。最近我遇到一个问题：需要让页面在调用完某个函数之后自动执行我的函数。
其实这个并不难，写个函数替换原有的函数即可：</p>
<pre>function hook() {
  var f = unsafeWindow.foo;         // 保存旧函数
  unsafeWindow.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                // 先执行我们的处理
    f();                            // 再执行旧函数
  }
}</pre>
<p>然后加载到页面上：</p>
<pre>setTimeout(hook, 1000);</pre>
<p>这样，页面再执行foo函数时，就会先执行我们的alert(&quot;Hello!&quot;)了。</p>
<p>不过这个函数还有很大的问题。比如，原有函数的参数不能正确传给foo，返回值无法取出来，无法应用到对象中的方法，通用性不好等。
下面来一个个解决。</p>
<!-- end Pukiwiki generated code--><span id="more-686"></span><!-- begin Pukiwiki generated code--><p>返回值的问题比较好办，让它return一下就行了：</p>
<pre>function hook() {
  var f = unsafeWindow.foo;         // 保存旧函数
  unsafeWindow.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                // 先执行我们的处理
    return f();                     // 再执行旧函数
}</pre>
<p>对象方法的意思是，如果要hook的函数不是全局函数，而是某个对象的方法的话，上述函数就无法正确执行。</p>
<pre>var object = {
  value: 10,
  foo: function () { alert(&quot;Foo!&quot; + this.value); }
};
object.foo();</pre>
<p>此时如果只是简单修改一下最初的GreaseMonkey脚本，改成这样的话：</p>
<pre>// 注意这种实现方法是错误的！
function hook() {
  var f = unsafeWindow.object.foo;         // 保存旧函数
  unsafeWindow.object.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                       // 先执行我们的处理
    return f();                            // 再执行旧函数
  }
}</pre>
<p>那么执行foo()时你会发现，本应输出&quot;Foo!10&quot;，但实际输出结果变成了&quot;Foo!undefined&quot;。
这是因为临时保存下来的 f 函数在执行时没有绑定到unsafeWindow.object上，因此找不到this.value。</p>
<p>解决方法是在调用 f 时使用 apply：</p>
<pre>// 正确的方法
function hook() {
  var f = unsafeWindow.object.foo;         // 保存旧函数
  unsafeWindow.object.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                       // 先执行我们的处理
    return f.apply(unsafeWindow.object);   // 再执行旧函数
  }
}</pre>
<p>有了apply，参数问题也迎刃而解：</p>
<pre>function hook() {
  var f = unsafeWindow.object.foo;                    // 保存旧函数
  unsafeWindow.object.foo = function() {              // 定义新函数
    alert(&quot;Hello!&quot;);                                  // 先执行我们的处理
    return f.apply(unsafeWindow.object, arguments);   // 再执行旧函数
  }
}</pre>
<p>最后的问题就是这个函数通用性还不好。代码中把要hook的函数(unsafeWindow.object.foo)写死了，
这样每hook一个函数都要写专用的函数才行。下面试着让它通用一些：</p>
<pre>/**
 * hook系统中的已有函数
 * @param object {Object} 要hook的函数所在的对象
 * @param name {String} 要hook的函数名称
 * @param pre {Function} 原函数执行前要执行的动作
 * @param post {Function} 原函数执行后要执行的动作
 * @return 旧函数的返回值
 */
function hook(object, func, pre, post) {
  var f = object[func];                       // 保存旧函数
  object[func] = function() {                 // 定义新函数
    if (pre) pre.apply(window, arguments);    // 旧函数执行前执行的自定义函数
    var ret = f.apply(object, arguments);     // 执行旧函数
    if (post) post.apply(window, arguments);  // 旧函数执行后执行的自定义函数
    return ret;
  }
}</pre>
<p>这样这个函数就相当通用了。在hook时需要执行以下代码：</p>
<pre>setTimeout(function() {
  hook(unsafeWindow.object, 
       &quot;foo&quot;, 
       function(){alert(&quot;pre&quot;)}, 
       function(){alert(&quot;post&quot;)}
  );
}, 1000);</pre>
<p>当然上述函数还有可以改进的地方。如调用pre和post时直接apply到了window上，
这样如果在hook时给出的pre和post不是全局函数而是某个对象的方法的话，
函数就无法正常执行了。不过对于一般的应用来说，上面的方法已经足够了吧。</p>
<!-- end Pukiwiki generated code-->
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>GreaseMonkey这个插件大家都早已熟悉了。最近我遇到一个问题：需要让页面在调用完某个函数之后自动执行我的函数。
其实这个并不难，写个函数替换原有的函数即可：</p>
<pre>function hook() {
  var f = unsafeWindow.foo;         // 保存旧函数
  unsafeWindow.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                // 先执行我们的处理
    f();                            // 再执行旧函数
  }
}</pre>
<p>然后加载到页面上：</p>
<pre>setTimeout(hook, 1000);</pre>
<p>这样，页面再执行foo函数时，就会先执行我们的alert(&quot;Hello!&quot;)了。</p>
<p>不过这个函数还有很大的问题。比如，原有函数的参数不能正确传给foo，返回值无法取出来，无法应用到对象中的方法，通用性不好等。
下面来一个个解决。</p>
<!-- end Pukiwiki generated code--><span id="more-686"></span><!-- begin Pukiwiki generated code--><p>返回值的问题比较好办，让它return一下就行了：</p>
<pre>function hook() {
  var f = unsafeWindow.foo;         // 保存旧函数
  unsafeWindow.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                // 先执行我们的处理
    return f();                     // 再执行旧函数
}</pre>
<p>对象方法的意思是，如果要hook的函数不是全局函数，而是某个对象的方法的话，上述函数就无法正确执行。</p>
<pre>var object = {
  value: 10,
  foo: function () { alert(&quot;Foo!&quot; + this.value); }
};
object.foo();</pre>
<p>此时如果只是简单修改一下最初的GreaseMonkey脚本，改成这样的话：</p>
<pre>// 注意这种实现方法是错误的！
function hook() {
  var f = unsafeWindow.object.foo;         // 保存旧函数
  unsafeWindow.object.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                       // 先执行我们的处理
    return f();                            // 再执行旧函数
  }
}</pre>
<p>那么执行foo()时你会发现，本应输出&quot;Foo!10&quot;，但实际输出结果变成了&quot;Foo!undefined&quot;。
这是因为临时保存下来的 f 函数在执行时没有绑定到unsafeWindow.object上，因此找不到this.value。</p>
<p>解决方法是在调用 f 时使用 apply：</p>
<pre>// 正确的方法
function hook() {
  var f = unsafeWindow.object.foo;         // 保存旧函数
  unsafeWindow.object.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                       // 先执行我们的处理
    return f.apply(unsafeWindow.object);   // 再执行旧函数
  }
}</pre>
<p>有了apply，参数问题也迎刃而解：</p>
<pre>function hook() {
  var f = unsafeWindow.object.foo;                    // 保存旧函数
  unsafeWindow.object.foo = function() {              // 定义新函数
    alert(&quot;Hello!&quot;);                                  // 先执行我们的处理
    return f.apply(unsafeWindow.object, arguments);   // 再执行旧函数
  }
}</pre>
<p>最后的问题就是这个函数通用性还不好。代码中把要hook的函数(unsafeWindow.object.foo)写死了，
这样每hook一个函数都要写专用的函数才行。下面试着让它通用一些：</p>
<pre>/**
 * hook系统中的已有函数
 * @param object {Object} 要hook的函数所在的对象
 * @param name {String} 要hook的函数名称
 * @param pre {Function} 原函数执行前要执行的动作
 * @param post {Function} 原函数执行后要执行的动作
 * @return 旧函数的返回值
 */
function hook(object, func, pre, post) {
  var f = object[func];                       // 保存旧函数
  object[func] = function() {                 // 定义新函数
    if (pre) pre.apply(window, arguments);    // 旧函数执行前执行的自定义函数
    var ret = f.apply(object, arguments);     // 执行旧函数
    if (post) post.apply(window, arguments);  // 旧函数执行后执行的自定义函数
    return ret;
  }
}</pre>
<p>这样这个函数就相当通用了。在hook时需要执行以下代码：</p>
<pre>setTimeout(function() {
  hook(unsafeWindow.object, 
       &quot;foo&quot;, 
       function(){alert(&quot;pre&quot;)}, 
       function(){alert(&quot;post&quot;)}
  );
}, 1000);</pre>
<p>当然上述函数还有可以改进的地方。如调用pre和post时直接apply到了window上，
这样如果在hook时给出的pre和post不是全局函数而是某个对象的方法的话，
函数就无法正常执行了。不过对于一般的应用来说，上面的方法已经足够了吧。</p>
<!-- end Pukiwiki generated code-->
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2009/03/16/hook-function-in-greasemonkey/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何在下载文件名中使用UTF-8编码</title>
		<link>http://tech.idv2.com/2009/03/05/use-utf8-in-download-filename/</link>
		<comments>http://tech.idv2.com/2009/03/05/use-utf8-in-download-filename/#comments</comments>
		<pubDate>Wed, 04 Mar 2009 17:53:28 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2009/03/05/use-utf8-in-download-filename/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>通过把Content-Type设置为application/octet-stream，
可以把动态生成的内容当作文件来下载，相信这个大家都会。
那么用Content-Disposition设置下载的文件名，
这个也有不少人知道吧。
基本上，下载程序都是这么写的：</p>
<pre>&lt;?php
$filename = &quot;document.txt&quot;;
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);

print &quot;Hello!&quot;;
?&gt;</pre>
<p>这样用浏览器打开之后，就可以下载document.doc。</p>
<p>但是，如果$filename是UTF-8编码的，有些浏览器就无法正常处理了。
比如把上面那个程序稍稍改一下：</p>
<pre>&lt;?php
$filename = &quot;中文 文件名.txt&quot;;
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);

print &quot;Hello!&quot;;
?&gt;</pre>
<p>把程序保存成UTF-8编码再访问，IE6下载的文件名就会乱码。
FF3下下载的文件名就只有“中文”两个字。Opera 9下一切正常。</p>
<!-- end Pukiwiki generated code--><span id="more-684"></span><!-- begin Pukiwiki generated code--><p>输出的header实际上是这样子：</p>
<pre>Content-Disposition: attachment; filename=中文 文件名.txt</pre>
<p>其实按照<a href="http://tools.ietf.org/html/rfc2231">RFC2231</a>的定义，
多语言编码的Content-Disposition应该这么定义：</p>
<pre>Content-Disposition: attachment; filename*=&quot;utf8''%E4%B8%AD%E6%96%87%20%E6%96%87%E4%BB%B6%E5%90%8D.txt&quot;</pre>
<p>即：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>filename后面的等号之前要加 *</li>
<li>filename的值用单引号分成三段，分别是字符集(utf8)、语言(空)和urlencode过的文件名。</li>
<li>最好加上双引号，否则文件名中空格后面的部分在Firefox中显示不出来</li>
<li>注意urlencode的结果与php的urlencode函数结果不太相同，php的urlencode会把空格替换成+，而这里需要替换成%20</li></ul>
<p>经过试验，发现几种主流浏览器的支持情况如下：</p>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">IE6</td><td class="style_td">attachment; filename=&quot;&lt;URL编码之后的UTF-8文件名&gt;&quot;</td></tr><tr><td class="style_td" rowspan="2">FF3</td><td class="style_td">attachment; filename=&quot;UTF-8文件名&quot;</td></tr><tr><td class="style_td">attachment; filename*=&quot;utf8''&lt;URL编码之后的UTF-8文件名&gt;&quot;</td></tr><tr><td class="style_td">O9</td><td class="style_td">attachment; filename=&quot;UTF-8文件名&quot;</td></tr><tr><td class="style_td">Safari3(Win)</td><td class="style_td">貌似不支持？上述方法都不行</td></tr></tbody></table></div>
<p>这样看来，程序必须得这样写才能支持所有主流浏览器：</p>
<pre>&lt;?php

$ua = $_SERVER[&quot;HTTP_USER_AGENT&quot;];

$filename = &quot;中文 文件名.txt&quot;;
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace(&quot;+&quot;, &quot;%20&quot;, $encoded_filename);

header('Content-Type: application/octet-stream');

if (preg_match(&quot;/MSIE/&quot;, $ua)) {
	header('Content-Disposition: attachment; filename=&quot;' . $encoded_filename . '&quot;');
} else if (preg_match(&quot;/Firefox/&quot;, $ua)) {
	header('Content-Disposition: attachment; filename*=&quot;utf8\'\'' . $filename . '&quot;');
} else {
	header('Content-Disposition: attachment; filename=&quot;' . $filename . '&quot;');
}

print 'ABC';
?&gt;
</pre>
<!-- end Pukiwiki generated code-->]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>通过把Content-Type设置为application/octet-stream，
可以把动态生成的内容当作文件来下载，相信这个大家都会。
那么用Content-Disposition设置下载的文件名，
这个也有不少人知道吧。
基本上，下载程序都是这么写的：</p>
<pre>&lt;?php
$filename = &quot;document.txt&quot;;
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);

print &quot;Hello!&quot;;
?&gt;</pre>
<p>这样用浏览器打开之后，就可以下载document.doc。</p>
<p>但是，如果$filename是UTF-8编码的，有些浏览器就无法正常处理了。
比如把上面那个程序稍稍改一下：</p>
<pre>&lt;?php
$filename = &quot;中文 文件名.txt&quot;;
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);

print &quot;Hello!&quot;;
?&gt;</pre>
<p>把程序保存成UTF-8编码再访问，IE6下载的文件名就会乱码。
FF3下下载的文件名就只有“中文”两个字。Opera 9下一切正常。</p>
<!-- end Pukiwiki generated code--><span id="more-684"></span><!-- begin Pukiwiki generated code--><p>输出的header实际上是这样子：</p>
<pre>Content-Disposition: attachment; filename=中文 文件名.txt</pre>
<p>其实按照<a href="http://tools.ietf.org/html/rfc2231">RFC2231</a>的定义，
多语言编码的Content-Disposition应该这么定义：</p>
<pre>Content-Disposition: attachment; filename*=&quot;utf8''%E4%B8%AD%E6%96%87%20%E6%96%87%E4%BB%B6%E5%90%8D.txt&quot;</pre>
<p>即：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>filename后面的等号之前要加 *</li>
<li>filename的值用单引号分成三段，分别是字符集(utf8)、语言(空)和urlencode过的文件名。</li>
<li>最好加上双引号，否则文件名中空格后面的部分在Firefox中显示不出来</li>
<li>注意urlencode的结果与php的urlencode函数结果不太相同，php的urlencode会把空格替换成+，而这里需要替换成%20</li></ul>
<p>经过试验，发现几种主流浏览器的支持情况如下：</p>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">IE6</td><td class="style_td">attachment; filename=&quot;&lt;URL编码之后的UTF-8文件名&gt;&quot;</td></tr><tr><td class="style_td" rowspan="2">FF3</td><td class="style_td">attachment; filename=&quot;UTF-8文件名&quot;</td></tr><tr><td class="style_td">attachment; filename*=&quot;utf8''&lt;URL编码之后的UTF-8文件名&gt;&quot;</td></tr><tr><td class="style_td">O9</td><td class="style_td">attachment; filename=&quot;UTF-8文件名&quot;</td></tr><tr><td class="style_td">Safari3(Win)</td><td class="style_td">貌似不支持？上述方法都不行</td></tr></tbody></table></div>
<p>这样看来，程序必须得这样写才能支持所有主流浏览器：</p>
<pre>&lt;?php

$ua = $_SERVER[&quot;HTTP_USER_AGENT&quot;];

$filename = &quot;中文 文件名.txt&quot;;
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace(&quot;+&quot;, &quot;%20&quot;, $encoded_filename);

header('Content-Type: application/octet-stream');

if (preg_match(&quot;/MSIE/&quot;, $ua)) {
	header('Content-Disposition: attachment; filename=&quot;' . $encoded_filename . '&quot;');
} else if (preg_match(&quot;/Firefox/&quot;, $ua)) {
	header('Content-Disposition: attachment; filename*=&quot;utf8\'\'' . $filename . '&quot;');
} else {
	header('Content-Disposition: attachment; filename=&quot;' . $filename . '&quot;');
}

print 'ABC';
?&gt;
</pre>
<!-- end Pukiwiki generated code-->]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2009/03/05/use-utf8-in-download-filename/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Web通信分析工具</title>
		<link>http://tech.idv2.com/2008/12/30/web-comm-analyzer/</link>
		<comments>http://tech.idv2.com/2008/12/30/web-comm-analyzer/#comments</comments>
		<pubDate>Tue, 30 Dec 2008 15:03:34 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[network]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2008/12/30/web-comm-analyzer/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>在抓虾上看到一篇Web开发分析工具的文章（链接就免了），怎么远没有我用的东西好用呢？
还是介绍介绍我用的吧。由于平常开发只用FireFox，完成后再去调试IE，
所以这些工具绝大部分是针对FireFox的。</p>
<p>如果把Web通信从上到下分为许多层——XMLHttpRequest层，HTTP层，TCP层，
那么这些工具可以分别抓取每个层的通信数据进行分析，结合使用极其强大。</p>
<p><strong>2008/12/31</strong>：另外可以参考daniel同学的<a href="http://hi.baidu.com/dearhwj/blog/item/c36283a738774d92d14358f7.html">Web开发常用工具</a>一文，相信会大有帮助哦。</p>
<!-- end Pukiwiki generated code--><span id="more-662"></span><!-- begin Pukiwiki generated code--><h2 id="content_20_0">XMLHttpRequest层：Firebug</h2>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">适用范围</td><td class="style_td">Ajax应用程序</td></tr><tr><td class="style_td">优点</td><td class="style_td">使用方便，数据截取完整</td></tr><tr><td class="style_td">缺点</td><td class="style_td">只能分析XMLHttpRequest请求，其他类型的请求无能为力</td></tr></tbody></table></div>
<p><a href="https://addons.mozilla.org/firefox/addon/1843">Firebug</a>应该是尽人皆知了。
它的控制台能监视XMLHttpRequest请求，能看到完整的请求和应答的数据。
用它来调试Ajax程序是最好不过了。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/firebug.png" alt="firebug.png" title="firebug.png" width="530" height="243" /></div>


<h2 id="content_20_1">HTTP层：Tamper Data</h2>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">适用范围</td><td class="style_td">普通网页，Ajax应用程序，Flash</td></tr><tr><td class="style_td">优点</td><td class="style_td">使用方便，适用范围广，任何HTTP请求都能截获</td></tr><tr><td class="style_td">缺点</td><td class="style_td">只能截获请求头、请求内容、应答头，得不到应答内容；涉及文件下载时效率大幅度降低</td></tr></tbody></table></div>
<p><a href="https://addons.mozilla.org/firefox/addon/966">Tamper Data</a>比Firebug进了一步，
只要是HTTP请求，它都能抓下来，可惜的是看不到应答内容。
适用于分析请求流程、请求参数、请求数据、重定向URL。
对于非Ajax程序如普通网页、Flash、ActiveX等程序，用Tamper Data来分析十分方便。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/tamperdata.png" alt="tamperdata.png" title="tamperdata.png" width="617" height="490" /></div>


<h2 id="content_20_2">HTTP层：burpsuite</h2>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">适用范围</td><td class="style_td">普通网页，Ajax应用程序，Flash</td></tr><tr><td class="style_td">优点</td><td class="style_td">适用范围广，截取数据完整，不挑网卡</td></tr><tr><td class="style_td">缺点</td><td class="style_td">使用稍稍麻烦</td></tr></tbody></table></div>
<p><a href="http://portswigger.net/suite/">burpsuite</a>中的proxy功能用于分析Web通信十分好用。
它的原理是架设一个代理服务器，让浏览器通过代理来发送请求，代理就可以截获数据了。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/burpsuite.png" alt="burpsuite.png" title="burpsuite.png" width="543" height="722" /></div>

<p>使用方法为：</p>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>配置proxy，然后设置浏览器使用它的proxy</li>
<li>访问想要抓取的那个网页</li>
<li>burp suite的proxy中就会看到请求内容，在这里即可详细地分析请求。</li>
<li>如果想继续分析应答，可以右键点击请求内容，选send to repeater</li>
<li>切换到repeater标签，点【go】按钮发送请求，在下方就可以看到应答</li></ol>

<h2 id="content_20_3">TCP层：wireshark</h2>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">适用范围</td><td class="style_td">任何网络程序</td></tr><tr><td class="style_td">优点</td><td class="style_td">适用范围广，截取数据完整</td></tr><tr><td class="style_td">缺点</td><td class="style_td">使用麻烦；不能使用loopback网卡</td></tr></tbody></table></div>
<p>如果以上方法都不管用，就要祭出终极武器<a href="http://www.wireshark.org/">wireshark</a>（原名ethereal）了。
它从网络的最底层入手，可以截获任何类型的网络通信，而不仅仅是HTTP协议。
比如要开发一个邮件程序，需要分析服务器端脚本与POP3服务器之间的通信，
那就非得wireshark出马不可了。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/wireshark.png" alt="wireshark.png" title="wireshark.png" width="550" height="408" /></div>

<p>使用方法：</p>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>在wireshark中选择抓取物理网卡；</li>
<li>让应用程序发请求；</li>
<li>在wireshark中停止抓取；</li>
<li>从抓到的包一览中找出刚才应用程序发出的请求，右键点击选择 Follow TCP Stream，就能看到该请求的完整内容。</li></ol>
<p>这个工具的不足之处是它不能抓取loopback的网卡，也就是说，
如果你的程序连接的是位于localhost或127.0.0.1的服务器，
那wireshark是抓不到的。解决方法是，让程序通过真实物理网卡去连别的机器，
或是使用虚拟机的虚拟网卡也行。</p>
<!-- end Pukiwiki generated code-->
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>在抓虾上看到一篇Web开发分析工具的文章（链接就免了），怎么远没有我用的东西好用呢？
还是介绍介绍我用的吧。由于平常开发只用FireFox，完成后再去调试IE，
所以这些工具绝大部分是针对FireFox的。</p>
<p>如果把Web通信从上到下分为许多层——XMLHttpRequest层，HTTP层，TCP层，
那么这些工具可以分别抓取每个层的通信数据进行分析，结合使用极其强大。</p>
<p><strong>2008/12/31</strong>：另外可以参考daniel同学的<a href="http://hi.baidu.com/dearhwj/blog/item/c36283a738774d92d14358f7.html">Web开发常用工具</a>一文，相信会大有帮助哦。</p>
<!-- end Pukiwiki generated code--><span id="more-662"></span><!-- begin Pukiwiki generated code--><h2 id="content_22_0">XMLHttpRequest层：Firebug</h2>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">适用范围</td><td class="style_td">Ajax应用程序</td></tr><tr><td class="style_td">优点</td><td class="style_td">使用方便，数据截取完整</td></tr><tr><td class="style_td">缺点</td><td class="style_td">只能分析XMLHttpRequest请求，其他类型的请求无能为力</td></tr></tbody></table></div>
<p><a href="https://addons.mozilla.org/firefox/addon/1843">Firebug</a>应该是尽人皆知了。
它的控制台能监视XMLHttpRequest请求，能看到完整的请求和应答的数据。
用它来调试Ajax程序是最好不过了。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/firebug.png" alt="firebug.png" title="firebug.png" width="530" height="243" /></div>


<h2 id="content_22_1">HTTP层：Tamper Data</h2>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">适用范围</td><td class="style_td">普通网页，Ajax应用程序，Flash</td></tr><tr><td class="style_td">优点</td><td class="style_td">使用方便，适用范围广，任何HTTP请求都能截获</td></tr><tr><td class="style_td">缺点</td><td class="style_td">只能截获请求头、请求内容、应答头，得不到应答内容；涉及文件下载时效率大幅度降低</td></tr></tbody></table></div>
<p><a href="https://addons.mozilla.org/firefox/addon/966">Tamper Data</a>比Firebug进了一步，
只要是HTTP请求，它都能抓下来，可惜的是看不到应答内容。
适用于分析请求流程、请求参数、请求数据、重定向URL。
对于非Ajax程序如普通网页、Flash、ActiveX等程序，用Tamper Data来分析十分方便。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/tamperdata.png" alt="tamperdata.png" title="tamperdata.png" width="617" height="490" /></div>


<h2 id="content_22_2">HTTP层：burpsuite</h2>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">适用范围</td><td class="style_td">普通网页，Ajax应用程序，Flash</td></tr><tr><td class="style_td">优点</td><td class="style_td">适用范围广，截取数据完整，不挑网卡</td></tr><tr><td class="style_td">缺点</td><td class="style_td">使用稍稍麻烦</td></tr></tbody></table></div>
<p><a href="http://portswigger.net/suite/">burpsuite</a>中的proxy功能用于分析Web通信十分好用。
它的原理是架设一个代理服务器，让浏览器通过代理来发送请求，代理就可以截获数据了。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/burpsuite.png" alt="burpsuite.png" title="burpsuite.png" width="543" height="722" /></div>

<p>使用方法为：</p>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>配置proxy，然后设置浏览器使用它的proxy</li>
<li>访问想要抓取的那个网页</li>
<li>burp suite的proxy中就会看到请求内容，在这里即可详细地分析请求。</li>
<li>如果想继续分析应答，可以右键点击请求内容，选send to repeater</li>
<li>切换到repeater标签，点【go】按钮发送请求，在下方就可以看到应答</li></ol>

<h2 id="content_22_3">TCP层：wireshark</h2>
<div class="ie5"><table class="style_table" cellspacing="1" border="0"><tbody><tr><td class="style_td">适用范围</td><td class="style_td">任何网络程序</td></tr><tr><td class="style_td">优点</td><td class="style_td">适用范围广，截取数据完整</td></tr><tr><td class="style_td">缺点</td><td class="style_td">使用麻烦；不能使用loopback网卡</td></tr></tbody></table></div>
<p>如果以上方法都不管用，就要祭出终极武器<a href="http://www.wireshark.org/">wireshark</a>（原名ethereal）了。
它从网络的最底层入手，可以截获任何类型的网络通信，而不仅仅是HTTP协议。
比如要开发一个邮件程序，需要分析服务器端脚本与POP3服务器之间的通信，
那就非得wireshark出马不可了。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/wireshark.png" alt="wireshark.png" title="wireshark.png" width="550" height="408" /></div>

<p>使用方法：</p>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>在wireshark中选择抓取物理网卡；</li>
<li>让应用程序发请求；</li>
<li>在wireshark中停止抓取；</li>
<li>从抓到的包一览中找出刚才应用程序发出的请求，右键点击选择 Follow TCP Stream，就能看到该请求的完整内容。</li></ol>
<p>这个工具的不足之处是它不能抓取loopback的网卡，也就是说，
如果你的程序连接的是位于localhost或127.0.0.1的服务器，
那wireshark是抓不到的。解决方法是，让程序通过真实物理网卡去连别的机器，
或是使用虚拟机的虚拟网卡也行。</p>
<!-- end Pukiwiki generated code-->
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/12/30/web-comm-analyzer/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>[新书预告]创建高可用性的Web内容</title>
		<link>http://tech.idv2.com/2008/12/19/design-accessible-web-sites-cn/</link>
		<comments>http://tech.idv2.com/2008/12/19/design-accessible-web-sites-cn/#comments</comments>
		<pubDate>Fri, 19 Dec 2008 09:54:13 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[accessibility]]></category>
		<category><![CDATA[book]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2008/12/19/design-accessible-web-sites-cn/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>经过两个多月的努力，这本名为《Web开发修炼之道——创建高可用性的Web内容》
（<a href="http://www.douban.com/subject/3598757/">豆瓣链接</a>，
<a href="http://blog.csdn.net/bvbook/archive/2009/03/23/4017111.aspx">出版社预告</a>，
<a href="http://tech.idv2.com/2009/04/21/design-accessible-web-sites-errata/">勘误表</a>）的书终于要与大家见面了。
这恐怕是国内第一本讨论可用性（Accessibility）的中文书籍——在豆瓣上搜索“可用性”，
找到的都是usability、availability等，没发现 accessibility。
可能这也是中国的网站在可用性方面做得很差的原因之一吧。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/design-accessible-web-sites-cn.jpg" alt="design-accessible-web-sites-cn.jpg" title="design-accessible-web-sites-cn.jpg" width="402" height="500" /></div>

<p>原书名为《Design Accessible Web Sites》（<a href="http://www.douban.com/subject/2373551/">豆瓣链接</a>），
书很不错，刚刚开始翻译时fcicq还在豆瓣上推荐了一把。
<del>不过我现在还没拿到书的ISBN，所以暂时没法将中文版放到豆瓣上，抱歉。拿到时再补上吧。</del></p>
<p>简单介绍一下书的内容吧。可用性（Accessibility）就是说让网站能在任何平台、任何浏览器上运行，
并且残障人士也能毫无障碍地使用网站。这就要求开发网站时必须做到：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>符合标准（以便跨浏览器跨平台）</li>
<li>为图片、视频等加上文字描述（供不支持图片的浏览器使用，同时考虑盲人所用的屏幕阅读器）</li>
<li>使用易于阅读的字体和颜色（考虑弱视、色盲）</li>
<li>使用简洁易懂的语言（考虑理解能力弱的用户）</li>
<li>足够大的导航和链接（让运动不方便的用户容易点击）</li>
<li>避免使用闪烁效果（防止诱发癫痫症）</li></ul>
<p>不幸的是，国内的网站在这些方面做得极其差劲（原谅我用极其这个词），
特别是本该为残障人士周全地考虑的政府网站，在这方面简直是一片空白。
希望这本书能为国内的网站设计提供参考。</p>
<p>下面是本书的内容简介，请点开阅读。</p>
<!-- end Pukiwiki generated code--><span id="more-649"></span><!-- begin Pukiwiki generated code--><p>可用性（accessibility）这个概念在中国虽然已渐渐流传开来，但是远远没有达到“深入人心”的地步。
特别是本应具有高可用性的政府网站、企业网站，却由于网站制作者在可用性方面的认识的缺乏，
使得残障人士无法正常使用，甚至连非Windows、非Internet Explorer的用户都很难访问。
而这方面的资料也仅限于一些公式化的原则和指南，鲜有具体教程和实际案例。</p>
<p>本书的出现正好填补了这一空白。本书是关于可用性的为数不多的书籍中的佼佼者，
它从可用性的缘由、基础结构、外观、应用程序可用性和法律法规等角度，
详细阐述了网站结构、布局、文本内容、图像、视频、音频、Flash、
PDF乃至Office文档等各个方面的可用性，内容翔实，语言通俗易懂。</p>
<p>本书面向的主要读者是有一定网站开发基础的程序员、界面设计师、内容编辑。
尤其推荐网站开发团队的领导者阅读。相信本书能帮你明确项目愿景、
促进项目进行、降低成本，并为中国互联网环境的可用性发展增添一份力量。</p>
<!-- end Pukiwiki generated code-->
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>经过两个多月的努力，这本名为《Web开发修炼之道——创建高可用性的Web内容》
（<a href="http://www.douban.com/subject/3598757/">豆瓣链接</a>，
<a href="http://blog.csdn.net/bvbook/archive/2009/03/23/4017111.aspx">出版社预告</a>，
<a href="http://tech.idv2.com/2009/04/21/design-accessible-web-sites-errata/">勘误表</a>）的书终于要与大家见面了。
这恐怕是国内第一本讨论可用性（Accessibility）的中文书籍——在豆瓣上搜索“可用性”，
找到的都是usability、availability等，没发现 accessibility。
可能这也是中国的网站在可用性方面做得很差的原因之一吧。</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2008/12/design-accessible-web-sites-cn.jpg" alt="design-accessible-web-sites-cn.jpg" title="design-accessible-web-sites-cn.jpg" width="402" height="500" /></div>

<p>原书名为《Design Accessible Web Sites》（<a href="http://www.douban.com/subject/2373551/">豆瓣链接</a>），
书很不错，刚刚开始翻译时fcicq还在豆瓣上推荐了一把。
<del>不过我现在还没拿到书的ISBN，所以暂时没法将中文版放到豆瓣上，抱歉。拿到时再补上吧。</del></p>
<p>简单介绍一下书的内容吧。可用性（Accessibility）就是说让网站能在任何平台、任何浏览器上运行，
并且残障人士也能毫无障碍地使用网站。这就要求开发网站时必须做到：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>符合标准（以便跨浏览器跨平台）</li>
<li>为图片、视频等加上文字描述（供不支持图片的浏览器使用，同时考虑盲人所用的屏幕阅读器）</li>
<li>使用易于阅读的字体和颜色（考虑弱视、色盲）</li>
<li>使用简洁易懂的语言（考虑理解能力弱的用户）</li>
<li>足够大的导航和链接（让运动不方便的用户容易点击）</li>
<li>避免使用闪烁效果（防止诱发癫痫症）</li></ul>
<p>不幸的是，国内的网站在这些方面做得极其差劲（原谅我用极其这个词），
特别是本该为残障人士周全地考虑的政府网站，在这方面简直是一片空白。
希望这本书能为国内的网站设计提供参考。</p>
<p>下面是本书的内容简介，请点开阅读。</p>
<!-- end Pukiwiki generated code--><span id="more-649"></span><!-- begin Pukiwiki generated code--><p>可用性（accessibility）这个概念在中国虽然已渐渐流传开来，但是远远没有达到“深入人心”的地步。
特别是本应具有高可用性的政府网站、企业网站，却由于网站制作者在可用性方面的认识的缺乏，
使得残障人士无法正常使用，甚至连非Windows、非Internet Explorer的用户都很难访问。
而这方面的资料也仅限于一些公式化的原则和指南，鲜有具体教程和实际案例。</p>
<p>本书的出现正好填补了这一空白。本书是关于可用性的为数不多的书籍中的佼佼者，
它从可用性的缘由、基础结构、外观、应用程序可用性和法律法规等角度，
详细阐述了网站结构、布局、文本内容、图像、视频、音频、Flash、
PDF乃至Office文档等各个方面的可用性，内容翔实，语言通俗易懂。</p>
<p>本书面向的主要读者是有一定网站开发基础的程序员、界面设计师、内容编辑。
尤其推荐网站开发团队的领导者阅读。相信本书能帮你明确项目愿景、
促进项目进行、降低成本，并为中国互联网环境的可用性发展增添一份力量。</p>
<!-- end Pukiwiki generated code-->
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/12/19/design-accessible-web-sites-cn/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>memcached全面剖析&#8211;PDF总结篇</title>
		<link>http://tech.idv2.com/2008/08/17/memcached-pdf/</link>
		<comments>http://tech.idv2.com/2008/08/17/memcached-pdf/#comments</comments>
		<pubDate>Sun, 17 Aug 2008 14:55:11 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[memcached]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2008/08/17/memcached-pdf/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>memcached全面剖析的连载已经结束，翻译工作也已经全部完成了。
为了方便阅读，现将原来的翻译结果打包成PDF文档。可在本文末尾处下载。</p>
<p>原来的各篇翻译的地址如下：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>第1章：<a href="http://tech.idv2.com/2008/07/10/memcached-001/">http://tech.idv2.com/2008/07/10/memcached-001/</a></li>
<li>第2章：<a href="http://tech.idv2.com/2008/07/11/memcached-002/">http://tech.idv2.com/2008/07/11/memcached-002/</a></li>
<li>第3章：<a href="http://tech.idv2.com/2008/07/16/memcached-003/">http://tech.idv2.com/2008/07/16/memcached-003/</a></li>
<li>第4章：<a href="http://tech.idv2.com/2008/07/24/memcached-004/">http://tech.idv2.com/2008/07/24/memcached-004/</a></li>
<li>第5章：<a href="http://tech.idv2.com/2008/07/31/memcached-005/">http://tech.idv2.com/2008/07/31/memcached-005/</a></li></ul>
<div class="img_margin" style="text-align:left"><a href="http://tech.idv2.com/wp-content/uploads/2008/08/memcached.zip" title="memcached全面剖析的PDF版"><img src="http://tech.idv2.com/wp-content/plugins/wp-pukiwiki/img/attach.gif" width="16" height="16" alt="attach" style="border-width:0px" />memcached.zip</a></div>

<!-- end Pukiwiki generated code-->]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>memcached全面剖析的连载已经结束，翻译工作也已经全部完成了。
为了方便阅读，现将原来的翻译结果打包成PDF文档。可在本文末尾处下载。</p>
<p>原来的各篇翻译的地址如下：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>第1章：<a href="http://tech.idv2.com/2008/07/10/memcached-001/">http://tech.idv2.com/2008/07/10/memcached-001/</a></li>
<li>第2章：<a href="http://tech.idv2.com/2008/07/11/memcached-002/">http://tech.idv2.com/2008/07/11/memcached-002/</a></li>
<li>第3章：<a href="http://tech.idv2.com/2008/07/16/memcached-003/">http://tech.idv2.com/2008/07/16/memcached-003/</a></li>
<li>第4章：<a href="http://tech.idv2.com/2008/07/24/memcached-004/">http://tech.idv2.com/2008/07/24/memcached-004/</a></li>
<li>第5章：<a href="http://tech.idv2.com/2008/07/31/memcached-005/">http://tech.idv2.com/2008/07/31/memcached-005/</a></li></ul>
<div class="img_margin" style="text-align:left"><a href="http://tech.idv2.com/wp-content/uploads/2008/08/memcached.zip" title="memcached全面剖析的PDF版"><img src="http://tech.idv2.com/wp-content/plugins/wp-pukiwiki/img/attach.gif" width="16" height="16" alt="attach" style="border-width:0px" />memcached.zip</a></div>

<!-- end Pukiwiki generated code-->]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/08/17/memcached-pdf/feed/</wfw:commentRss>
		<slash:comments>60</slash:comments>
		</item>
		<item>
		<title>闪烁和感光症</title>
		<link>http://tech.idv2.com/2008/08/16/flicker-and-photosensitive-epilepsy/</link>
		<comments>http://tech.idv2.com/2008/08/16/flicker-and-photosensitive-epilepsy/#comments</comments>
		<pubDate>Fri, 15 Aug 2008 17:08:44 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[accessibility]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2008/08/16/flicker-and-photosensitive-epliepsy/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p><a href="http://en.wikipedia.org/wiki/Photosensitive_epilepsy">感光症癫痫（Photosensitive Epilepsy）</a>
是一种罕见的癫痫症。高速闪烁的灯光、连续出现的图案、闪烁的视频，甚至树叶被风吹动时摇曳的影子都有可能会引起感光症发作。</p>
<p>感光症引起各国的重视，是由于1997年的<a href="http://ja.wikipedia.org/wiki/%E3%83%9D%E3%82%B1%E3%83%A2%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%82%AF">口袋妖怪事件</a>。
1997年12月16日，《口袋妖怪》第38话《电脑战士3D龙》在日本播出。该片为了表现电脑内部的爆炸效果，
而多次使用了红-&gt;蓝-&gt;红-&gt;蓝的高速颜色切换，导致日本全国约750名儿童被送往医院，其中150人需要住院治疗。
因此导致《口袋妖怪》被停播数月，恢复后，导致事故发生的主角“3D龙”也没能在电视中继续出现。</p>
<p>所以现在日本的动画片开头都会添加字幕，请观众在观看时远离屏幕，并打开室内灯光，以减少感光症发作的可能性。</p>
<p>而在2007年播放的一段2012年伦敦奥运会宣传片上，由于使用了闪烁效果，也导致了英国数人感光症发作。</p>
<p>下面这段视频就是被禁播的《电脑战士3D龙》。大家可以注意10:13、11:48、14:56、15:54和17:39的闪烁镜头。
不过，有感光症的读者还是不要看的好。</p>
<p><span style="color:red"><strong>警告：以下视频包含强烈的闪烁，请在观看时自行承担一切责任。特别是有感光症癫痫史的读者请不要观看。</strong></span></p>
<p><span style="color:red"><strong>WARNING: The following video contains flicker effects. Please take responsibility yourself while watching. DO NOT watch if you have photosensitive epliepsy.</strong></span></p>
<p><span style="color:red"><strong>警告：下記のビデオに激しい光の点滅が含まれています。視聴は自己責任でお願いします。特に光過敏性症候群の方はプレイしないでください。</strong></span></p>
<!-- end Pukiwiki generated code-->
<span id="more-629"></span>
<embed src="http://player.youku.com/player.php/sid/XMjQ0MDM2MzI=/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"></embed>
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p><a href="http://en.wikipedia.org/wiki/Photosensitive_epilepsy">感光症癫痫（Photosensitive Epilepsy）</a>
是一种罕见的癫痫症。高速闪烁的灯光、连续出现的图案、闪烁的视频，甚至树叶被风吹动时摇曳的影子都有可能会引起感光症发作。</p>
<p>感光症引起各国的重视，是由于1997年的<a href="http://ja.wikipedia.org/wiki/%E3%83%9D%E3%82%B1%E3%83%A2%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%82%AF">口袋妖怪事件</a>。
1997年12月16日，《口袋妖怪》第38话《电脑战士3D龙》在日本播出。该片为了表现电脑内部的爆炸效果，
而多次使用了红-&gt;蓝-&gt;红-&gt;蓝的高速颜色切换，导致日本全国约750名儿童被送往医院，其中150人需要住院治疗。
因此导致《口袋妖怪》被停播数月，恢复后，导致事故发生的主角“3D龙”也没能在电视中继续出现。</p>
<p>所以现在日本的动画片开头都会添加字幕，请观众在观看时远离屏幕，并打开室内灯光，以减少感光症发作的可能性。</p>
<p>而在2007年播放的一段2012年伦敦奥运会宣传片上，由于使用了闪烁效果，也导致了英国数人感光症发作。</p>
<p>下面这段视频就是被禁播的《电脑战士3D龙》。大家可以注意10:13、11:48、14:56、15:54和17:39的闪烁镜头。
不过，有感光症的读者还是不要看的好。</p>
<p><span style="color:red"><strong>警告：以下视频包含强烈的闪烁，请在观看时自行承担一切责任。特别是有感光症癫痫史的读者请不要观看。</strong></span></p>
<p><span style="color:red"><strong>WARNING: The following video contains flicker effects. Please take responsibility yourself while watching. DO NOT watch if you have photosensitive epliepsy.</strong></span></p>
<p><span style="color:red"><strong>警告：下記のビデオに激しい光の点滅が含まれています。視聴は自己責任でお願いします。特に光過敏性症候群の方はプレイしないでください。</strong></span></p>
<!-- end Pukiwiki generated code-->
<span id="more-629"></span>
<embed src="http://player.youku.com/player.php/sid/XMjQ0MDM2MzI=/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"></embed>
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/08/16/flicker-and-photosensitive-epilepsy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache报告No space left on device的解决办法</title>
		<link>http://tech.idv2.com/2008/08/15/apache-no-space-left-on-device/</link>
		<comments>http://tech.idv2.com/2008/08/15/apache-no-space-left-on-device/#comments</comments>
		<pubDate>Fri, 15 Aug 2008 05:16:03 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2008/08/15/apache-no-space-left-on-device/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>今天在开发时突然apache无法启动了。表现为，输入 httpd -X 后片刻自动退出，
同时在error_log中有如下内容：</p>
<pre>[Fri Aug 15 10:54:31 2008] [emerg] (28)No space left on device: Couldn't create accept lock</pre>
<p>df一下发现不是磁盘空间的问题。Google了一下就找到了解决方案，原来是系统的信号量(?)不够用了。
用以下命令可以查看所有的信号量：</p>
<pre># ipcs -s
------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x00000000 19234816   nobody    600        1
0x00000000 19267585   nobody    600        1
0x00000000 19300354   nobody    600        1
0x00000000 19398659   nobody    600        1
0x00000000 19431428   nobody    600        1
0x00000000 19464197   nobody    600        1
0x00000000 19562502   nobody    600        1</pre>
<p>然后用这行命令删除所有的信号量即可：</p>
<pre>ipcs -s | grep nobody | perl -lane 'print `ipcrm sem $F[1]`'</pre>
<!-- end Pukiwiki generated code-->
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>今天在开发时突然apache无法启动了。表现为，输入 httpd -X 后片刻自动退出，
同时在error_log中有如下内容：</p>
<pre>[Fri Aug 15 10:54:31 2008] [emerg] (28)No space left on device: Couldn't create accept lock</pre>
<p>df一下发现不是磁盘空间的问题。Google了一下就找到了解决方案，原来是系统的信号量(?)不够用了。
用以下命令可以查看所有的信号量：</p>
<pre># ipcs -s
------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x00000000 19234816   nobody    600        1
0x00000000 19267585   nobody    600        1
0x00000000 19300354   nobody    600        1
0x00000000 19398659   nobody    600        1
0x00000000 19431428   nobody    600        1
0x00000000 19464197   nobody    600        1
0x00000000 19562502   nobody    600        1</pre>
<p>然后用这行命令删除所有的信号量即可：</p>
<pre>ipcs -s | grep nobody | perl -lane 'print `ipcrm sem $F[1]`'</pre>
<!-- end Pukiwiki generated code-->
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/08/15/apache-no-space-left-on-device/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
