<?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>Vimer的程序世界 &#187; 程序设计</title>
	<atom:link href="http://www.vimer.cn/category/program/feed" rel="self" type="application/rss+xml" />
	<link>http://www.vimer.cn</link>
	<description></description>
	<lastBuildDate>Thu, 17 May 2012 11:40:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>bottle高级使用技巧</title>
		<link>http://www.vimer.cn/2012/04/bottle%e9%ab%98%e7%ba%a7%e4%bd%bf%e7%94%a8%e6%8a%80%e5%b7%a7.html</link>
		<comments>http://www.vimer.cn/2012/04/bottle%e9%ab%98%e7%ba%a7%e4%bd%bf%e7%94%a8%e6%8a%80%e5%b7%a7.html#comments</comments>
		<pubDate>Fri, 20 Apr 2012 02:50:58 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[bottle.]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[flask]]></category>
		<category><![CDATA[get_url]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2532</guid>
		<description><![CDATA[之前对bottle做过不少的介绍，也写过一些文章来说明bottle的缺点，最近发现其实之前有些地方说的不太公平，所以趁此机会也来更正一下。 bottle是支持类似flask url_for的语法的，具体使用方法在... ]]></description>
			<content:encoded><![CDATA[<p>之前对<a href="http://bottlepy.org/" target="_blank" >bottle</a>做过不少的介绍，也写过一些文章来说明bottle的缺点，最近发现其实之前有些地方说的不太公平，所以趁此机会也来更正一下。</p>
<ul>
<li>bottle是支持类似flask url_for的语法的，具体使用方法在下文介绍</li>
<li>bottle的request.query之类的参数默认是str类型，也是有原因的，比如我在给google做代理的时候，编码就不一定是utf8的，如果强制转化utf8就会报错</li>
<li>之前的bug也得到了修正，比如mount('/x',app)之后，/x/和/x都可以访问到</li>
</ul>
<p>OK，现在正式进入主题，我们来介绍一些bottle的一些高级使用</p>
<p><b><br />
一. 智能创建url<br />
</b><br />
这部分在bottle的文档上是没有介绍的（其实bottle明明实现了很多贴心的功能，不知道为啥都不写在文档上）。<br />
在Bottle类里，有一个成员函数:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> get_url<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, routename, <span style="color: #66cc66;">**</span>kargs<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Return a string that matches a named route &quot;&quot;&quot;</span>
    scriptname = request.<span style="color: black;">environ</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'SCRIPT_NAME'</span>, <span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'/'</span>
    location = <span style="color: #008000;">self</span>.<span style="color: black;">router</span>.<span style="color: black;">build</span><span style="color: black;">&#40;</span>routename, <span style="color: #66cc66;">**</span>kargs<span style="color: black;">&#41;</span>.<span style="color: black;">lstrip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> urljoin<span style="color: black;">&#40;</span>urljoin<span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span>, scriptname<span style="color: black;">&#41;</span>, location<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>那么这个routename是哪里来的呢？看 route 装饰器的参数:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> route<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, path=<span style="color: #008000;">None</span>, method=<span style="color: #483d8b;">'GET'</span>, callback=<span style="color: #008000;">None</span>, name=<span style="color: #008000;">None</span>,
          apply=<span style="color: #008000;">None</span>, skip=<span style="color: #008000;">None</span>, <span style="color: #66cc66;">**</span>config<span style="color: black;">&#41;</span>:</pre></td></tr></table></div>

<p>其中的name参数就是routename（这里不得不说一下，这种方式比flask要好些，要用才指定name，而不需要为了实现url_for，把整个框架都实现的很复杂）</p>
<p>所以看到这里大家也就明白了，bottle的url生成器是绑定在Bottle实例上的，所以跨实例访问默认是做不到的。<br />
而可能由于bottle所推崇的micro化，所以其源码中特意对默认Bottle示例包装出了一个函数:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> name <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'route get post put delete error mount
               hook install uninstall'</span><span style="color: #483d8b;">''</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #008000;">globals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>name<span style="color: black;">&#93;</span> = make_default_app_wrapper<span style="color: black;">&#40;</span>name<span style="color: black;">&#41;</span>
url = make_default_app_wrapper<span style="color: black;">&#40;</span><span style="color: #483d8b;">'get_url'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">del</span> name</pre></td></tr></table></div>

<p>这样做的好处是，如果工程只用到默认的Bottle实例的话，在模板中就可以直接使用url，而不必再多传个Bottle实例进去。</p>
<p>但是难免的，有时候我们确实涉及到跨实例生成url的，有没有办法呢？当然是有的，比较简单的方法如下:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> default_app
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> x
&nbsp;
local.<span style="color: black;">x_app</span> = x.<span style="color: black;">app</span>
&nbsp;
app.<span style="color: black;">mount</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/x'</span>, x.<span style="color: black;">app</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>这样在模板中就可以直接通过如下方式来访问:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">{{ local.x_app.get_url('hello', name='ai', x=1) }}</pre></td></tr></table></div>

<p>但是怎么才能让模板能够访问到local变量呢？我们接下来介绍</p>
<p><b><br />
二. 给模板指定默认的变量<br />
</b><br />
因为笔者用的最多的是jinja2，所以模板相关的介绍都是以jinja2为例子.<br />
由于bottle的很多实例都是使用的代理模式，如request,response,local，所以我们可以放心的将这些变量传入到模板默认变量里去。<br />
代码也很简单：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> BaseTemplate
&nbsp;
BaseTemplate.<span style="color: black;">defaults</span>.<span style="color: black;">update</span><span style="color: black;">&#40;</span><span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>
    request=request,
    local=local,
    <span style="color: black;">&#41;</span>
<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>有兴趣的话，大家也可以去直接看一下源码，很好懂</p>
<p><b><br />
三. 给模板增加filters<br />
</b><br />
还是以jinja2为例，直接给出代码如下:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> BaseTemplate
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'filters'</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> BaseTemplate.<span style="color: black;">settings</span>:
    BaseTemplate.<span style="color: black;">settings</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'filters'</span><span style="color: black;">&#93;</span> = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
&nbsp;
filters = BaseTemplate.<span style="color: black;">settings</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'filters'</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> urlencode_filter<span style="color: black;">&#40;</span>params<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
    urlencode
    '</span><span style="color: #483d8b;">''</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">urllib</span> <span style="color: #ff7700;font-weight:bold;">import</span> urlencode
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> urlencode<span style="color: black;">&#40;</span>params<span style="color: black;">&#41;</span>
&nbsp;
filters.<span style="color: black;">update</span><span style="color: black;">&#40;</span><span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>
    urlencode=urlencode_filter,
    <span style="color: black;">&#41;</span>
<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>OK，一共就是这些，这里基于的bottle版本是 0.10.9，如果有不相符的地方，请查看bottle版本。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/04/bottle%e9%ab%98%e7%ba%a7%e4%bd%bf%e7%94%a8%e6%8a%80%e5%b7%a7.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>最近的一些技术整理（20120405）</title>
		<link>http://www.vimer.cn/2012/04/%e6%9c%80%e8%bf%91%e7%9a%84%e4%b8%80%e4%ba%9b%e6%8a%80%e6%9c%af%e6%95%b4%e7%90%86%ef%bc%8820120405%ef%bc%89.html</link>
		<comments>http://www.vimer.cn/2012/04/%e6%9c%80%e8%bf%91%e7%9a%84%e4%b8%80%e4%ba%9b%e6%8a%80%e6%9c%af%e6%95%b4%e7%90%86%ef%bc%8820120405%ef%bc%89.html#comments</comments>
		<pubDate>Thu, 05 Apr 2012 12:24:27 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[uwsgi]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2525</guid>
		<description><![CDATA[还是和往常一样，没啥主题，就是记录下这段时间遇到的技术问题，分享一下。 1. 在javascript中实现简单的模板替换 最近搞了一下js，最不习惯的就是字符串生成都要用字符串拼装或者join的方... ]]></description>
			<content:encoded><![CDATA[<p>还是和往常一样，没啥主题，就是记录下这段时间遇到的技术问题，分享一下。</p>
<p><strong>1. 在javascript中实现简单的模板替换</strong></p>
<p>最近搞了一下js，最不习惯的就是字符串生成都要用字符串拼装或者join的方式，所以尝试一下看能否实现简单的模板替换，效果还不错。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> str_format<span style="color: #009900;">&#40;</span>str<span style="color: #339933;">,</span> obj<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">return</span> str.<span style="color: #660066;">replace</span><span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/\{\s*(\w+)\s*\}/g</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>_i<span style="color: #339933;">,</span> _1<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000066; font-weight: bold;">return</span> obj<span style="color: #009900;">&#91;</span>_1<span style="color: #009900;">&#93;</span> <span style="color: #339933;">!=</span> <span style="color: #003366; font-weight: bold;">null</span> <span style="color: #339933;">?</span> obj<span style="color: #009900;">&#91;</span>_1<span style="color: #009900;">&#93;</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">''</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>很多朋友会说性能差一些，可能确实如此，不过对我来说，相比编写的舒适来说，这点性能差别实在无足轻重了。</p>
<p><strong>2. uwsgi报readv() faild</strong></p>
<p>用uwsgi+nginx搭建的server，发现当用post请求时，会返回数据超时。查了一下uwsgi的error.log:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">9825#0: *745262 readv() failed (104: Connection reset by peer) while reading upstream, client: 121.14.96.125</pre></td></tr></table></div>

<p>后来在网上搜了一下文档：<br />
<a href="http://comments.gmane.org/gmane.comp.python.wsgi.uwsgi.general/1021" target="_blank" >http://comments.gmane.org/gmane.comp.python.wsgi.uwsgi.general/1021</a></p>
<p>其解释说解决方案有两种：<br />
在uwsgi执行参数上增加：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #660033;">--pep333-input</span>
<span style="color: #660033;">--post-buffering</span> <span style="color: #000000;">4096</span></pre></td></tr></table></div>

<p>试了一下，只有第二种有效，所以由于google了一下命令的具体含义：</p>
<p>
post-buffering<br />
打开http body缓冲, 如果HTTP body的大小超过指定的限制,那么就保存到磁盘上.
</p>
<p>参考链接：<br />
<a href="http://simple-is-better.com/news/301" target="_blank" >http://simple-is-better.com/news/301</a></p>
<p>OK，就是这样~</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/04/%e6%9c%80%e8%bf%91%e7%9a%84%e4%b8%80%e4%ba%9b%e6%8a%80%e6%9c%af%e6%95%b4%e7%90%86%ef%bc%8820120405%ef%bc%89.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>nginx自定义模块编写-根据post参数路由到不同服务器</title>
		<link>http://www.vimer.cn/2012/03/nginx%e8%87%aa%e5%ae%9a%e4%b9%89%e6%a8%a1%e5%9d%97%e7%bc%96%e5%86%99-%e6%a0%b9%e6%8d%aepost%e5%8f%82%e6%95%b0%e8%b7%af%e7%94%b1%e5%88%b0%e4%b8%8d%e5%90%8c%e6%9c%8d%e5%8a%a1%e5%99%a8-2.html</link>
		<comments>http://www.vimer.cn/2012/03/nginx%e8%87%aa%e5%ae%9a%e4%b9%89%e6%a8%a1%e5%9d%97%e7%bc%96%e5%86%99-%e6%a0%b9%e6%8d%aepost%e5%8f%82%e6%95%b0%e8%b7%af%e7%94%b1%e5%88%b0%e4%b8%8d%e5%90%8c%e6%9c%8d%e5%8a%a1%e5%99%a8-2.html#comments</comments>
		<pubDate>Sun, 04 Mar 2012 16:56:39 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[开源项目]]></category>
		<category><![CDATA[nginx+lua]]></category>
		<category><![CDATA[nginx扩展模块]]></category>
		<category><![CDATA[nginx自定义模块]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2511</guid>
		<description><![CDATA[nginx可以轻松实现根据不同的url 或者 get参数来转发到不同的服务器，然而当我们需要根据http包体来进行请求路由时，nginx默认的配置规则就捉襟见肘了，但是没关系，nginx提供了强大的自定义... ]]></description>
			<content:encoded><![CDATA[<p>nginx可以轻松实现根据不同的url 或者 get参数来转发到不同的服务器，然而当我们需要根据http包体来进行请求路由时，nginx默认的配置规则就捉襟见肘了，但是没关系，nginx提供了强大的自定义模块功能，我们只要进行需要的扩展就行了。</p>
<p>我们来理一下思路，我们的需求是：</p>
<p>
    nginx根据http包体的参数，来选择合适的路由
</p>
<p>在这之前，我们先来考虑另一个问题：</p>
<p><b>在nginx默认配置的支持下，能否实现服务器间的跳转呢？即类似于状态机，从一个服务器执行OK后，跳转到另一台服务器，按照规则依次传递下去。</b></p>
<p>答案是可以的，这也是我之前写<a href="http://code.google.com/p/bayonet/" target="_blank" >bayonet</a>之后，在nginx上特意尝试的功能。</p>
<p>一个示例的配置如下:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="conf" style="font-family:monospace;">server {
    listen       8080;
    server_name  localhost;
&nbsp;
    location / {
        proxy_pass http://localhost:8888;
&nbsp;
        error_page 433 = @433;
        error_page 434 = @434;
    }
    location @433 {
        proxy_pass http://localhost:6788;
    }
    location @434 {
        proxy_pass http://localhost:6789;
    }
&nbsp;
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
&nbsp;
}</pre></td></tr></table></div>

<p>看明白了吧？我们使用了 433和434 这两个非标准http协议的返回码，所有请求进入时都默认进入 http://localhost:8888;，然后再根据返回码是 433 还是 434 来选择进入 http://localhost:6788 还是 http://localhost:6789。</p>
<p>OK，也许你已经猜到我将这个例子的用意了，是的，我们只要在我们的自定义模块中，根据http的包体返回不同的返回码，进而 proxy_pass 到不同的后端服务器即可。</p>
<p>好吧，接下来，我们正式进入nginx自定义模块的编写中来。</p>
<p><b>一. nginx 自定义模块编写</b><br />
由于这也是我第一次写nginx模块，所以也是参考了非常多文档，我一一列在这里，所以详细的入门就不说了，只说比较不太一样的地方。<br />
参考链接:</p>
<ol>
<li><a href="http://haoningabc.iteye.com/blog/1283098" target="_blank" >nginx的helloworld模块的helloworld</a></li>
<li><a href="http://lijinxing17.blog.163.com/blog/static/349777082010627104929343/" target="_blank" >nginx 一个例子模块，简单的将http请求的内容返输出</a></li>
<li><a href="http://blog.chinaunix.net/space.php?uid=26443921&#038;do=blog&#038;id=3018781" target="_blank" >nginx 自定义协议 扩展模块开发</a></li>
<li><a href="http://yaoweibin.cn/maindoc/nginx-modules-guide-cn.pdf" target="_blank" >Emiller的Nginx模块开发指南</a></li>
</ol>
<p>而我们这个模块一个最大的特点就是，需要等包体整个接收完才能进行处理，所以有如下代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> ngx_http_foo_post_handler<span style="color: #008000;">&#40;</span>ngx_http_request_t <span style="color: #000040;">*</span>r<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
    <span style="color: #666666;">// 请求全部读完后从这里入口, 可以产生响应</span>
    ngx_http_request_body_t<span style="color: #000040;">*</span> rb <span style="color: #000080;">=</span> r<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>request_body<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> body <span style="color: #000080;">=</span> <span style="color: #0000ff;">NULL</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> body_size <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>rb <span style="color: #000040;">&amp;&amp;</span> rb<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>buf<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        body <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>rb<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>buf<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>pos<span style="color: #008080;">;</span>
        body_size <span style="color: #000080;">=</span> rb<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>buf<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>last <span style="color: #000040;">-</span> rb<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>buf<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>pos<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">int</span> result <span style="color: #000080;">=</span> get_route_id<span style="color: #008000;">&#40;</span>r<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>connection<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span><span style="color: #0000dd;">log</span>, 
                              <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span>r<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>method,
                              <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>r<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>uri.<span style="color: #007788;">data</span>,
                              <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>r<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>args.<span style="color: #007788;">data</span>,
                              body,
                              body_size
                              <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>result <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        ngx_log_error<span style="color: #008000;">&#40;</span>NGX_LOG_ERR, r<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>connection<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span><span style="color: #0000dd;">log</span>, <span style="color: #0000dd;">0</span>, <span style="color: #FF0000;">&quot;get_route_id fail, result:%d&quot;</span>, result<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        result <span style="color: #000080;">=</span> DFT_ROUTE_ID<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    ngx_http_finalize_request<span style="color: #008000;">&#40;</span>r, result<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">static</span> ngx_int_t ngx_http_req_route_handler<span style="color: #008000;">&#40;</span>ngx_http_request_t <span style="color: #000040;">*</span>r<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    ngx_http_read_client_request_body<span style="color: #008000;">&#40;</span>r, ngx_http_foo_post_handler<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> NGX_DONE<span style="color: #008080;">;</span> <span style="color: #666666;">// 主handler结束</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>我们注册了一个回调函数 ngx_http_foo_post_handler，当包体全部接受完成时就会调用。之后我们调用了get_route_id来获取返回码，然后通过 ngx_http_finalize_request(r, result);　来告诉nginx处理的结果。</p>
<p>这里有个小插曲，即get_route_id。我们来看一下它定义的原型:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">extern</span> <span style="color: #0000ff;">int</span> get_route_id<span style="color: #008000;">&#40;</span>ngx_log_t <span style="color: #000040;">*</span><span style="color: #0000dd;">log</span>, <span style="color: #0000ff;">int</span> method, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> uri, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> args, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> body, <span style="color: #0000ff;">int</span> body_size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>第一个参数是 ngx_log_t *log，是为了方便在报错的时候打印日志。然而在最开始的时候，get_route_id 的原型是这样：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">extern</span> <span style="color: #0000ff;">int</span> get_route_id<span style="color: #008000;">&#40;</span>ngx_http_request_t <span style="color: #000040;">*</span>r, <span style="color: #0000ff;">int</span> method, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> uri, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> args, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> body, <span style="color: #0000ff;">int</span> body_size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>结果在 get_route_id 函数内部，调用</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">r<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>connection<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span><span style="color: #0000dd;">log</span></pre></td></tr></table></div>

<p>的结果总是null，至今也不知道为什么。（知道了是lua头文件和ngx头文件顺序的问题，把ngx头文件放到最前面即可）</p>
<p>OK，接下来我们只要在get_route_id中增加逻辑代码，读几行配置，判断一下就可以了~ 但是，我想要的远不止如此。</p>
<p><b>二.lua解析器的加入</b><br />
老博友应该都看过我之前写的一篇博客: <a href="http://www.vimer.cn/?p=2328" target="_blank" >代码即数据，数据即代码（1）-把难以变更的代码变成易于变更的数据</a>，而这一次的需求也非常符合使用脚本的原则:</p>
<p><b>只需要告诉我返回nginx哪个返回码，具体怎么算出来的，再复杂，再多变，都放到脚本里面去。</b></p>
<p>所以接下来我又写了c调用lua的代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> get_route_id<span style="color: #008000;">&#40;</span>ngx_log_t <span style="color: #000040;">*</span><span style="color: #0000dd;">log</span>, <span style="color: #0000ff;">int</span> method, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> uri, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> args, <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> body, <span style="color: #0000ff;">int</span> body_size<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> lua_funcname<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;get_route_id&quot;</span><span style="color: #008080;">;</span>
&nbsp;
    lua_State <span style="color: #000040;">*</span>L <span style="color: #000080;">=</span> luaL_newstate<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    luaL_openlibs<span style="color: #008000;">&#40;</span>L<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>luaL_loadfile<span style="color: #008000;">&#40;</span>L, LUA_FILENAME<span style="color: #008000;">&#41;</span> <span style="color: #000040;">||</span> lua_pcall<span style="color: #008000;">&#40;</span>L, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        ngx_log_error<span style="color: #008000;">&#40;</span>NGX_LOG_ERR, <span style="color: #0000dd;">log</span>, <span style="color: #0000dd;">0</span>, <span style="color: #FF0000;">&quot;cannot run configuration file: %s&quot;</span>, lua_tostring<span style="color: #008000;">&#40;</span>L, <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        lua_close<span style="color: #008000;">&#40;</span>L<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    lua_getglobal<span style="color: #008000;">&#40;</span>L, lua_funcname<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #ff0000; font-style: italic;">/* function to be called */</span>
    lua_pushnumber<span style="color: #008000;">&#40;</span>L, method<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    lua_pushstring<span style="color: #008000;">&#40;</span>L, uri<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    lua_pushstring<span style="color: #008000;">&#40;</span>L, args<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    lua_pushlstring<span style="color: #008000;">&#40;</span>L, body, body_size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #ff0000; font-style: italic;">/* do the call (1 arguments, 1 result) */</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>lua_pcall<span style="color: #008000;">&#40;</span>L, <span style="color: #0000dd;">4</span>, <span style="color: #0000dd;">1</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">!</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        ngx_log_error<span style="color: #008000;">&#40;</span>NGX_LOG_ERR, <span style="color: #0000dd;">log</span>, <span style="color: #0000dd;">0</span>, <span style="color: #FF0000;">&quot;error running function %s: %s&quot;</span>, lua_funcname, lua_tostring<span style="color: #008000;">&#40;</span>L, <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        lua_close<span style="color: #008000;">&#40;</span>L<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">2</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #ff0000; font-style: italic;">/* retrieve result */</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>lua_isnumber<span style="color: #008000;">&#40;</span>L, <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        ngx_log_error<span style="color: #008000;">&#40;</span>NGX_LOG_ERR, <span style="color: #0000dd;">log</span>, <span style="color: #0000dd;">0</span>, <span style="color: #FF0000;">&quot;function %s must return a number&quot;</span>, lua_funcname<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        lua_close<span style="color: #008000;">&#40;</span>L<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">3</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">int</span> result <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span>lua_tonumber<span style="color: #008000;">&#40;</span>L, <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    lua_pop<span style="color: #008000;">&#40;</span>L, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #ff0000; font-style: italic;">/* pop returned value */</span>
&nbsp;
    lua_close<span style="color: #008000;">&#40;</span>L<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> result<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>比较郁闷的是，lua 5.2的很多函数都变了，比如lua_open废弃，变成luaL_newstate等，不过总体来说还算没浪费太多时间。</p>
<p>接下来是req_route.lua的内容，我只截取入口函数如下:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><pre class="lua" style="font-family:monospace;"><span style="color: #b1b100;">function</span> get_route_id<span style="color: #66cc66;">&#40;</span>method, uri, args, body<span style="color: #66cc66;">&#41;</span>
&nbsp;
    loc, pf ,appid <span style="color: #66cc66;">=</span> get_need_vals<span style="color: #66cc66;">&#40;</span>method, uri, args, body<span style="color: #66cc66;">&#41;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> loc <span style="color: #66cc66;">==</span> <span style="color: #b1b100;">nil</span> <span style="color: #b1b100;">or</span> pf <span style="color: #66cc66;">==</span> <span style="color: #b1b100;">nil</span> <span style="color: #b1b100;">or</span> appid <span style="color: #66cc66;">==</span> <span style="color: #b1b100;">nil</span> <span style="color: #b1b100;">then</span>
        <span style="color: #b1b100;">return</span> OUT_CODE
    <span style="color: #b1b100;">end</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">--到这里位置，就把所有的数据都拿到了</span>
    <span style="color: #808080; font-style: italic;">--print (loc, pf, appid)</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">-- 找是否在对应的url, loc中</span>
    <span style="color: #b1b100;">if</span> <span style="color: #b1b100;">not</span> is_match_pf_and_loc<span style="color: #66cc66;">&#40;</span>pf, loc<span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">then</span>
        <span style="color: #b1b100;">return</span> OUT_CODE
    <span style="color: #b1b100;">end</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">-- 找是否在对应的appid中</span>
    <span style="color: #b1b100;">if</span> <span style="color: #b1b100;">not</span> is_match_appid<span style="color: #66cc66;">&#40;</span>appid<span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">then</span>
        <span style="color: #b1b100;">return</span> OUT_CODE
    <span style="color: #b1b100;">end</span>
&nbsp;
    <span style="color: #b1b100;">return</span> IN_CODE
<span style="color: #b1b100;">end</span></pre></td></tr></table></div>

<p>OK，结合了lua解析器之后，无论多复杂的调整，我们都基本可以做到只修改lua脚本而不需要重新修改、编译nginx模块代码了。</p>
<p>接下来，就该是体验我们的成果了。<br />
<b>三.nginx配置</b></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="conf" style="font-family:monospace;">server {
    listen       8080;
    server_name  localhost;
&nbsp;
    location /req_route {
        req_route;
        error_page 433 = @433;
        error_page 434 = @434;
    }
    location @433 {
        proxy_pass http://localhost:6788;
    }
    location @434 {
        proxy_pass http://localhost:6789;
    }
&nbsp;
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
&nbsp;
}</pre></td></tr></table></div>

<p>OK，enjoy it！</p>
<p>最后，放出代码如下:<br />
<a href="https://vimercode.googlecode.com/svn/trunk/nginx_req_route" target="_blank" >https://vimercode.googlecode.com/svn/trunk/nginx_req_route</a></p>
<hr />
用perl or lua的版本如下<br />
<a href="http://www.php-oa.com/2010/09/25/perl-perl-nginx.html" target="_blank" >http://www.php-oa.com/2010/09/25/perl-perl-nginx.html</a><br />
<a href="https://github.com/chaoslawful/lua-nginx-module" target="_blank" >https://github.com/chaoslawful/lua-nginx-module</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/03/nginx%e8%87%aa%e5%ae%9a%e4%b9%89%e6%a8%a1%e5%9d%97%e7%bc%96%e5%86%99-%e6%a0%b9%e6%8d%aepost%e5%8f%82%e6%95%b0%e8%b7%af%e7%94%b1%e5%88%b0%e4%b8%8d%e5%90%8c%e6%9c%8d%e5%8a%a1%e5%99%a8-2.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>橡树果项目正式开源</title>
		<link>http://www.vimer.cn/2012/02/%e6%a9%a1%e6%a0%91%e6%9e%9c%e9%a1%b9%e7%9b%ae%e6%ad%a3%e5%bc%8f%e5%bc%80%e6%ba%90.html</link>
		<comments>http://www.vimer.cn/2012/02/%e6%a9%a1%e6%a0%91%e6%9e%9c%e9%a1%b9%e7%9b%ae%e6%ad%a3%e5%bc%8f%e5%bc%80%e6%ba%90.html#comments</comments>
		<pubDate>Mon, 13 Feb 2012 12:43:00 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[开源项目]]></category>
		<category><![CDATA[xiangshuguo]]></category>
		<category><![CDATA[xiangshuguo.com]]></category>
		<category><![CDATA[开源]]></category>
		<category><![CDATA[橡树果]]></category>
		<category><![CDATA[橡树果开源]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2496</guid>
		<description><![CDATA[很早之前在博客中提到过笔者用bottle写了一个简单的图片分享网站--橡树果(http://xiangshuguo.com，目前网站在筹划升级v2版，所以暂时不可用)，当时由于项目代码本身的不成熟，所以没有开源。 今... ]]></description>
			<content:encoded><![CDATA[<p>很早之前在博客中提到过笔者用<a href="http://bottlepy.org/" target="_blank" >bottle</a>写了一个简单的图片分享网站--橡树果(<a href="http://xiangshuguo.com" target="_blank" >http://xiangshuguo.com</a>，目前网站在筹划升级v2版，所以暂时不可用)，当时由于项目代码本身的不成熟，所以没有开源。<br />
今天正式将其开源，希望能对使用微框架（如bottle or flask）开发的朋友，或者想要一窥python web开发的朋友提供一些参考。</p>
<p>项目地址:<br />
<a href="http://code.google.com/p/xiangshuguo/" target="_blank" >http://code.google.com/p/xiangshuguo/</a></p>
<p>先给大家来张截图，宏观上看一下：</p>
<p><a href="http://www.vimer.cn/wp-content/uploads/2012/02/1.png" target="_blank" ><img title="http://www.vimer.cn/wp-content/uploads/2012/02/1.png" src="http://www.vimer.cn/wp-content/uploads/2012/02/1.png" width="570" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" alt="1" border="0" /></a></p>
<p>其实简单来说，橡树果主要是实现一个自由的图片分享功能，用户能够自由上传，浏览。</p>
<p><b>其使用的技术如下: </b></p>
<ul>
<li>web框架</li>
<p>    使用微框架<a href="http://bottlepy.org/" target="_blank" >bottle</a>。<br />
    <a href="http://bottlepy.org/" target="_blank" >bottle</a>是个非常小巧的框架，只有一个文件，3000多行，代码我也基本上都读了一遍。</p>
<li>ORM</li>
<p>    选用了简单的<a href="http://autumn-orm.org/" target="_blank" >autumn</a>，因为并不会用到复杂的关系数据。但是由于其本身的限制，所以对齐做了一些修改。</p>
<li>模板</li>
<p>    模板使用 <a href="http://www.pocoo.org/projects/jinja2/#jinja2" target="_blank" >jinja2</a>，本身贴近django模板的语法，用起来也很熟悉。</p>
<li>form类</li>
<p>    form类使用 <a href="http://wtforms.simplecodes.com/" target="_blank" >WTForms</a>。</p>
<li>数据库</li>
<p>    数据库使用 sqlite，部署方便
</ul>
<p><b>安装说明:</b></p>
<ul>
<li>执行python init_env.py来初始化数据库，执行成功在目录下会产生一个data.db</li>
<li>如果是调试，执行python myapp.py启动程序，访问127.0.0.1:8080</li>
<li>如果正式部署，在linux下执行uws.sh</li>
</ul>
<p><b>橡树果本身限制:</b><br />
由于代码本身写的很仓促，所以仔细看代码就会发现，橡树果会一次性获取所有图片列表，这一点前台的性能影响很大，不过苦于对js的生疏，所以如果有朋友能一起来优化这里，笔者会非常欢迎</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/02/%e6%a9%a1%e6%a0%91%e6%9e%9c%e9%a1%b9%e7%9b%ae%e6%ad%a3%e5%bc%8f%e5%bc%80%e6%ba%90.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>web开发框架的选择(bottle or flask)及为autumn增加多线程支持</title>
		<link>http://www.vimer.cn/2012/02/web%e5%bc%80%e5%8f%91%e6%a1%86%e6%9e%b6%e7%9a%84%e9%80%89%e6%8b%a9bottle-or-flask%e5%8f%8a%e4%b8%baautumn%e5%a2%9e%e5%8a%a0%e5%a4%9a%e7%ba%bf%e7%a8%8b%e6%94%af%e6%8c%81.html</link>
		<comments>http://www.vimer.cn/2012/02/web%e5%bc%80%e5%8f%91%e6%a1%86%e6%9e%b6%e7%9a%84%e9%80%89%e6%8b%a9bottle-or-flask%e5%8f%8a%e4%b8%baautumn%e5%a2%9e%e5%8a%a0%e5%a4%9a%e7%ba%bf%e7%a8%8b%e6%94%af%e6%8c%81.html#comments</comments>
		<pubDate>Sun, 12 Feb 2012 11:14:32 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[autumn]]></category>
		<category><![CDATA[autumn多线程支持]]></category>
		<category><![CDATA[bottle.]]></category>
		<category><![CDATA[flask]]></category>
		<category><![CDATA[web开发框架]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2492</guid>
		<description><![CDATA[其实之前就有写过关于python web开发框架选择的文章，之前最终选择了bottle，并给出了bottle开发的物理设计，详见之前的文章：回归简单，向Django说再见、bottle做web开发的物理设计，然而经过最... ]]></description>
			<content:encoded><![CDATA[<p>其实之前就有写过关于python web开发框架选择的文章，之前最终选择了bottle，并给出了bottle开发的物理设计，详见之前的文章：<a href="http://www.vimer.cn/2011/11/%E5%9B%9E%E5%BD%92%E7%AE%80%E5%8D%95%EF%BC%8C%E5%90%91django%E8%AF%B4%E5%86%8D%E8%A7%81.html" target="_blank" >回归简单，向Django说再见</a>、<a href="http://www.vimer.cn/2011/12/bottle%E5%81%9Aweb%E5%BC%80%E5%8F%91%E7%9A%84%E7%89%A9%E7%90%86%E8%AE%BE%E8%AE%A1.html" target="_blank" >bottle做web开发的物理设计</a>，然而经过最近两个星期的实践，又有了一些新的想法。</p>
<p>Bottle作为一个微框架，本身确实有些小型项目的缺点，尝试列举如下:</p>
<ul>
<li>没有原生支持unicode</li>
<p>    例如route('/<name>')获取的name并不是unicode类型，get和post的参数也默认并非unicode类型，虽然作者后来在0.10版本中给query和forms加入attr方式来解决这个问题，但是还是有所限制<br />
    而flask则是 unicode based，对unicode支持的非常好</p>
<li>影响力小，与其他组件的结合比较差</li>
<p>    一个典型的例子就是wtforms不支持bottle的files字段，而flask虽然也不支持，但是flask的插件flask-wtforms则完美修正了这个问题</p>
<li>功能太基本</li>
<p>    关于这一点，可以说是优点也可以说是缺点。绝对的纯粹看起来是件好事，但是真正开发起来又发现完全不是那么回事，自己要重新开发的轮子实在太多了。比如session的支持</p>
<li>bottle由个人开发，有些地方并不那么专业</li>
<p>    比如route的参数method=['GET','POST']，因为是数组，所以用methods更合适；request.forms其实用request.form更合适<br />
    再比如static_file函数，必须要求传入一个root_path和一个filename；而flask则有两个函数一个send_file和send_from_directory，支持直接返回file内容
</ul>
<p>反观flask，不能说flask的一切都是好的，但是确实在这几点上要比bottle做的要好一些，而且flask还有一些很实用的功能，比如实时debug，还有一些很实用的函数如url_for，而且flask与django确实有很大的相似性，这对flask本身的成熟度有很大的提高。</p>
<p>当然，实事求是，flask确实在设计上要比bottle复杂了很多，而且依赖了werkzeug，所以到现在我代码也没有读完，这一点也确实是让我之前迟迟没有选择flask的原因。</p>
<p>所以综合上述的理由，笔者最终决定从bottle重新转向flask，而值得一提的是之前用bottle写成的橡树果图片分享站，由bottle改成flask花了不到一个小时的时间~</p>
<p>OK，关于框架的选择就到这里。</p>
<p><b><br />
接下来还有个问题，就是之前有提到过的autumn库。<br />
</b><br />
无论是flask还是bottle，其框架都是支持多线程的，而我们的autumn却只支持单线程，所以特意做了一下修改，其实代码也比较简单，修改的代码如下：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#ADD-BEGIN by dantezhu in 2012-02-10 02:30:57</span>
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">threading</span> <span style="color: #ff7700;font-weight:bold;">import</span> local
&nbsp;
local_data = local<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">#ADD-END</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Database<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    placeholder = <span style="color: #483d8b;">'?'</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> connect<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, dbtype, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
<span style="color: #808080; font-style: italic;">#Add-Begin by dantezhu in 2011-12-16 01:56:34</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">dbtype</span> = dbtype
<span style="color: #808080; font-style: italic;">#Add-End</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> dbtype == <span style="color: #483d8b;">'sqlite3'</span>:
            <span style="color: #ff7700;font-weight:bold;">import</span> sqlite3
            <span style="color: #008000;">self</span>.<span style="color: black;">connection</span> = sqlite3.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">elif</span> dbtype == <span style="color: #483d8b;">'mysql'</span>:
            <span style="color: #ff7700;font-weight:bold;">import</span> MySQLdb
            <span style="color: #008000;">self</span>.<span style="color: black;">connection</span> = MySQLdb.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">placeholder</span> = <span style="color: #483d8b;">'%s'</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#ADD-BEGIN by dantezhu in 2012-02-10 02:30:40</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__getattr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> key == <span style="color: #483d8b;">'connection'</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>local_data, key<span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">AttributeError</span>, <span style="color: #483d8b;">'the object has no attr: '</span> + key
                <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span>
&nbsp;
            <span style="color: #dc143c;">cmd</span> = <span style="color: #483d8b;">'local_data.'</span> + <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>key<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">eval</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">cmd</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">object</span>.<span style="color: #0000cd;">__getattr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__setattr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key, value<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> key == <span style="color: #483d8b;">'connection'</span>:
            <span style="color: #dc143c;">cmd</span> = <span style="color: #483d8b;">'local_data.'</span> + <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>key<span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'=value'</span>
            <span style="color: #ff7700;font-weight:bold;">exec</span> <span style="color: #dc143c;">cmd</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #008000;">object</span>.<span style="color: #0000cd;">__setattr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key, value<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">#ADD-END</span></pre></td></tr></table></div>

<p>使用了threading.local()这个变量，这样当获取 autumn_db.conn.connection 时就会是线程安全的了</p>
<p>老规矩，代码还是放在svn上:<br />
<a href="https://vimercode.googlecode.com/svn/trunk/bottle_site_tpl/depend/autumn" target="_blank" >https://vimercode.googlecode.com/svn/trunk/bottle_site_tpl/depend/autumn</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/02/web%e5%bc%80%e5%8f%91%e6%a1%86%e6%9e%b6%e7%9a%84%e9%80%89%e6%8b%a9bottle-or-flask%e5%8f%8a%e4%b8%baautumn%e5%a2%9e%e5%8a%a0%e5%a4%9a%e7%ba%bf%e7%a8%8b%e6%94%af%e6%8c%81.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>在windows7上开启虚拟wifi热点</title>
		<link>http://www.vimer.cn/2012/02/%e5%9c%a8windows7%e4%b8%8a%e5%bc%80%e5%90%af%e8%99%9a%e6%8b%9fwifi%e7%83%ad%e7%82%b9-2.html</link>
		<comments>http://www.vimer.cn/2012/02/%e5%9c%a8windows7%e4%b8%8a%e5%bc%80%e5%90%af%e8%99%9a%e6%8b%9fwifi%e7%83%ad%e7%82%b9-2.html#comments</comments>
		<pubDate>Sun, 12 Feb 2012 10:22:18 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[wifi热点]]></category>
		<category><![CDATA[热点]]></category>
		<category><![CDATA[虚拟wifi]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2488</guid>
		<description><![CDATA[前段时间家里的无线路由还没到，手机直接连电信的路由又没法拨号（万恶的电信），所以没办法只能尝试在windows7开启隐藏的虚拟wifi热点功能~~ OK，开始~ 1. 以管理员身份运行命令提示符 “开... ]]></description>
			<content:encoded><![CDATA[<p>前段时间家里的无线路由还没到，手机直接连电信的路由又没法拨号（万恶的电信），所以没办法只能尝试在windows7开启隐藏的虚拟wifi热点功能~~<br />
OK，开始~</p>
<p><b> 1. 以管理员身份运行命令提示符</b><br />
“开始”---在搜索栏输入“cmd”----右键以“管理员身份运行”</p>
<p><b> 2. 启用并设定虚拟WiFi网卡</b><br />
运行命令:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="txt" style="font-family:monospace;">netsh wlan set hostednetwork mode=allow ssid=dantezhu_wifi key=00000000</pre></td></tr></table></div>

<p>"ssid"后为网络名称，起个名字就行<br />
"Key"后为密码，一般要求是8位</p>
<p>执行完之后，打开“网络和共享中心”--“更改适配器设置”看看是不是多了一项，若果有多出的这一项“Microsoft Virtual WiFi Miniport Adapter”，为方便区分，将其改名为“虚拟wifi”。</p>
<p><a href="http://www.vimer.cn/wp-content/uploads/2012/01/虚拟wifi.png" target="_blank" ><img title="http://www.vimer.cn/wp-content/uploads/2012/01/虚拟wifi.png" src="http://www.vimer.cn/wp-content/uploads/2012/01/虚拟wifi.png" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" alt="1" border="0" /></a></p>
<p><b> 3.设置Internet连接共享</b><br />
在“网络连接”窗口中，右键单击已连接到Internet的网络连接，选择“属性”→“共享”，勾上“允许其他······连接(N)”并选择“虚拟WiFi”。 </p>
<p><a href="http://www.vimer.cn/wp-content/uploads/2012/01/2.jpg" target="_blank" ><img title="http://www.vimer.cn/wp-content/uploads/2012/01/2.jpg" src="http://www.vimer.cn/wp-content/uploads/2012/01/2.jpg" width="570" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" alt="1" border="0" /></a></p>
<p>这里要注意的是，如果像我一样采用宽带拨号，那么要更改的网络链接是那个“宽带链接”而不是“本地链接”</p>
<p><b>4.开启无线网络</b><br />
继续在命令提示符中运行:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="txt" style="font-family:monospace;">netsh wlan start hostednetwork</pre></td></tr></table></div>

<p>或者将命令存为bat文件，以管理员运行。方便每次开机时执行~</p>
<p><b> 5.配置静态IP </b><br />
上面第4步结束之后，我们的设备就可以连接上了，但这个时候很可能是上不了网的。需要我们静态配置一下。</p>
<p>a)电脑设置<br />
点击“更改适配器设置”-“虚拟wifi”属性------“ipv4”，修改成如下：</p>
<p><a href="http://www.vimer.cn/wp-content/uploads/2012/01/pc.jpg" target="_blank" ><img title="http://www.vimer.cn/wp-content/uploads/2012/01/pc.jpg" src="http://www.vimer.cn/wp-content/uploads/2012/01/pc.jpg" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" alt="1" border="0" /></a></p>
<p>b)手机设置<br />
iphone等无线设备的设置：打开iphone等上的无线网络，选择你设置无线网的名称，进入后选择“静态”<br />
第一行，ip地址填：192.168.137.X（X在2-254之间）<br />
第二行, 子网掩码：255.255.255.0<br />
第三行，路由器：192.168.137.1（电脑上虚拟网路是多少就填多少，不能填其它数值）<br />
<b>第四行：DNS : 8.8.8.8 （使用的google的dns，这里要注意，使用192.168.137.1是不行的！）</b></p>
<p>如果手机上的DNS配置有问题的话，就会出现很多朋友遇到的，手机能上QQ，但是上不了网的情况。</p>
<p>如果上面的步骤还是不能上网，就将PC的虚拟wifi的DNS也改成8.8.8.8试试</p>
<p>OK，到此结束~<br />
参考文章: <a href="http://bbs.weiphone.com/read-htm-tid-2167498.html" target="_blank" >将win7电脑变身WiFi热点(非connectify,APwifi)一种稳定，便捷，网速好的方法</a></p>
<p>PS:connectify真的是推荐大家不要用，我用了之后每次电脑都关不了机，总是强制关机，结果把硬盘搞坏了去换了一个。。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/02/%e5%9c%a8windows7%e4%b8%8a%e5%bc%80%e5%90%af%e8%99%9a%e6%8b%9fwifi%e7%83%ad%e7%82%b9-2.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>关于libcurl不发包的bug定位</title>
		<link>http://www.vimer.cn/2012/01/%e5%85%b3%e4%ba%8elibcurl%e4%b8%8d%e5%8f%91%e5%8c%85%e7%9a%84bug%e5%ae%9a%e4%bd%8d.html</link>
		<comments>http://www.vimer.cn/2012/01/%e5%85%b3%e4%ba%8elibcurl%e4%b8%8d%e5%8f%91%e5%8c%85%e7%9a%84bug%e5%ae%9a%e4%bd%8d.html#comments</comments>
		<pubDate>Wed, 11 Jan 2012 02:05:40 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[算法]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[libcurl]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2476</guid>
		<description><![CDATA[前几天同事的程序有个很奇怪的bug，跟大家分享一下。 描述如下：一个http接口在测试环境下能够正常访问，在外网环境下就会直接超时，并且超时的消耗是建是0ms。 我strace了一下，libcurl在测... ]]></description>
			<content:encoded><![CDATA[<p>前几天同事的程序有个很奇怪的bug，跟大家分享一下。<br />
描述如下：一个http接口在测试环境下能够正常访问，在外网环境下就会直接超时，并且超时的消耗是建是0ms。<br />
我strace了一下，libcurl在测试环境能正常发包，在外网环境却总是直接返回，连连接都没有尝试建立。</p>
<p>仔细研究了他的代码，发现并没有什么不合理之处，一筹莫展时发现有如下代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">curl_easy_setopt<span style="color: #008000;">&#40;</span>curl, CURLOPT_TIMEOUT_MS, <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>timeout_sec<span style="color: #000040;">*</span><span style="color: #0000dd;">1000</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>                                                        
curl_easy_setopt<span style="color: #008000;">&#40;</span>curl, CURLOPT_CONNECTTIMEOUT_MS, <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>timeout_sec<span style="color: #000040;">*</span><span style="color: #0000dd;">1000</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>突然想起之前有文章说curl只支持秒级的超时时间，而我们外网的超时配置的是0.5秒。<br />
把超时时间改成1秒之后，果然一切正常了。</p>
<p>google上搜了一下，在如下链接找到了答案:<br />
<a href="http://stackoverflow.com/questions/1856473/why-would-curl-ignore-curlopt-timeout-ms-but-honor-curlopt-timeout" target="_blank" >http://stackoverflow.com/questions/1856473/why-would-curl-ignore-curlopt-timeout-ms-but-honor-curlopt-timeout</a></p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">The version of curl I am using (7.15.5) doesn't support CURLOPT_TIMEOUT_MS. According to Greg I need at least 7.16.2.</pre></div></div>

<p>看了一下外网curl的版本:</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">user_00@RS_Server_appsupport:~&gt; curl --version
curl 7.15.1 (x86_64-suse-linux) libcurl/7.15.1 OpenSSL/0.9.8a zlib/1.2.3 libidn/0.6.0
Protocols: tftp ftp gopher telnet dict ldap http file https ftps 
Features: IDN IPv6 Largefile NTLM SSL libz</pre></div></div>

<p>果然是低于7.16.2。</p>
<p>问题到这里算是解决了，但是还有一个很奇怪的地方，就是我们测试环境的curl版本也是7.15.1，但是配置0.5秒用起来却没有任何问题。当然唯一不同的是，外网是64位，测试环境是是32位而已。</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">$ curl --version
curl 7.15.1 (i686-suse-linux) libcurl/7.15.1 OpenSSL/0.9.8a zlib/1.2.3 libidn/0.6.0
Protocols: tftp ftp gopher telnet dict ldap http file https ftps 
Features: IDN IPv6 Largefile NTLM SSL libz</pre></div></div>

<p>但是不管怎样，以后在curl中使用小于一秒的超时时，还是多加小心为妙。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/01/%e5%85%b3%e4%ba%8elibcurl%e4%b8%8d%e5%8f%91%e5%8c%85%e7%9a%84bug%e5%ae%9a%e4%bd%8d.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>最近的一些技术整理(20120109)</title>
		<link>http://www.vimer.cn/2012/01/%e6%9c%80%e8%bf%91%e7%9a%84%e4%b8%80%e4%ba%9b%e6%8a%80%e6%9c%af%e6%95%b4%e7%90%8620120109.html</link>
		<comments>http://www.vimer.cn/2012/01/%e6%9c%80%e8%bf%91%e7%9a%84%e4%b8%80%e4%ba%9b%e6%8a%80%e6%9c%af%e6%95%b4%e7%90%8620120109.html#comments</comments>
		<pubDate>Mon, 09 Jan 2012 12:41:19 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[MySql]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[xiangshuguo.com]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2457</guid>
		<description><![CDATA[前段时间一直没写博客，昨天更新了一篇，今天突然又来了兴致，那就再更新一篇吧（所以说啊，治疗拖延症最好的方法就是现在开始做） 这篇还是一些技术的整理，主要是用于备忘，大家如... ]]></description>
			<content:encoded><![CDATA[<p>前段时间一直没写博客，昨天更新了一篇，今天突然又来了兴致，那就再更新一篇吧（所以说啊，治疗拖延症最好的方法就是现在开始做）</p>
<p>这篇还是一些技术的整理，主要是用于备忘，大家如果觉得太简单就一笑而过啦~</p>
<p><b>一. python通过图片内容判断图片类型</b></p>
<p>前段时间写了一个小站练手，<a href="http://xiangshuguo.com" target="_blank" >http://xiangshuguo.com</a>，一个支持自由上传的图片小站。</p>
<p>因为要限制上传图片的格式，所以要做文件类型检测，代码如下:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> get_image_type<span style="color: black;">&#40;</span>pd, is_path=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
    获取图片的类型，支持传入路径和文件内容
    '</span><span style="color: #483d8b;">''</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> is_path:
        f = <span style="color: #008000;">file</span><span style="color: black;">&#40;</span>pd, <span style="color: #483d8b;">'rb'</span><span style="color: black;">&#41;</span>
        data = f.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'hex'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        data = pd.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'hex'</span><span style="color: black;">&#41;</span>
&nbsp;
    ftype = <span style="color: #008000;">None</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> data.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ffd8'</span><span style="color: black;">&#41;</span>:
        ftype = <span style="color: #483d8b;">'jpeg'</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> data.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'424d'</span><span style="color: black;">&#41;</span>:
        ftype = <span style="color: #483d8b;">'bmp'</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> data.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'474946'</span><span style="color: black;">&#41;</span>:
        ftype = <span style="color: #483d8b;">'gif'</span>
    <span style="color: #ff7700;font-weight:bold;">elif</span> data.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'89504e470d0a1a0a'</span><span style="color: black;">&#41;</span>:
        ftype = <span style="color: #483d8b;">'png'</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> ftype</pre></td></tr></table></div>

<p><b>二. stringstream使用陷阱（1）</b><br />
我直接举一个例子吧</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">stringstream ss<span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span> x<span style="color: #008080;">;</span>
&nbsp;
ss <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;190&quot;</span><span style="color: #008080;">;</span>
ss <span style="color: #000080;">&gt;&gt;</span> x<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> x<span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>这个代码是没有问题的，结果会是:</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">190</pre></div></div>

<p>如下的代码:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">stringstream ss<span style="color: #008080;">;</span>
string x<span style="color: #008080;">;</span>
&nbsp;
ss <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;190&quot;</span><span style="color: #008080;">;</span>
ss <span style="color: #000080;">&gt;&gt;</span> x<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> x<span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>也是没有问题的，输出也是：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">190</pre></div></div>

<p>然而这样的代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">stringstream ss<span style="color: #008080;">;</span>
string x<span style="color: #008080;">;</span>
&nbsp;
ss <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;x y z&quot;</span><span style="color: #008080;">;</span>
ss <span style="color: #000080;">&gt;&gt;</span> x<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> x<span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>输出将会是:</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">x</pre></div></div>

<p>好吧，看了文档才发现，当 stringstream将数据导出到一个字符串变量时，它会用空格分割。<br />
但说实话，同一个操作符，意义却不一样，这真挺让人纠结。。</p>
<p><b>三. stringstream使用陷阱（2）</b><br />
如果你习惯了C分割的atoi直接将空字符串转成0，那么用stringstream时，千万不要做这种事情，因为如下代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">stringstream ss<span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span> x<span style="color: #008080;">;</span>
ss <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;&quot;</span><span style="color: #008080;">;</span>
ss <span style="color: #000080;">&gt;&gt;</span> x<span style="color: #008080;">;</span>
<span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> x<span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>输出将并不一定是0。</p>
<p><b>四. MySQL多库表的查询方法</b><br />
腾讯内部使用MySQL数据库都是分库表的，所以在mysql中想手工查询个数据都会变得非常困难，所以这里放个简单的模板，要用的时候，只要用vim对应生成一下就可以了</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span><span style="color: #66cc66;">&#40;</span>
<span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> db_app_right0<span style="color: #66cc66;">.</span>tb_app_right0
<span style="color: #993333; font-weight: bold;">UNION</span>
<span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> db_app_right0<span style="color: #66cc66;">.</span>tb_app_right1
<span style="color: #66cc66;">&#41;</span><span style="color: #993333; font-weight: bold;">AS</span> t  <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #993333; font-weight: bold;">OUTFILE</span> <span style="color: #ff0000;">'/tmp/mx'</span>;</pre></td></tr></table></div>

<p><b>五. MySQL安全删除数据的做法</b><br />
这个其实是来自公司DBA的建议啦，这里分享一下</p>
<p>关于delete，我这里建议你们 做任何的delete操作之前先执行如下备份语句：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> backup<span style="color: #66cc66;">.</span>tablename <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> dbname<span style="color: #66cc66;">.</span>tablename  <span style="color: #993333; font-weight: bold;">WHERE</span> id <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">90000</span>;
<span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #993333; font-weight: bold;">FROM</span> dbname<span style="color: #66cc66;">.</span>tablename  <span style="color: #993333; font-weight: bold;">WHERE</span> id <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">90000</span>;</pre></td></tr></table></div>

<p>恢复语句：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">insert into dbname.<span style="color: #007788;">tablename</span> select <span style="color: #000040;">*</span> from backup.<span style="color: #007788;">tablename</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>还有一个习惯, 如果确信自己删的数据只有一条 加个 limit 1</p>
<p>OK，就这样</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/01/%e6%9c%80%e8%bf%91%e7%9a%84%e4%b8%80%e4%ba%9b%e6%8a%80%e6%9c%af%e6%95%b4%e7%90%8620120109.html/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>搭建nginx+wordpress调试环境</title>
		<link>http://www.vimer.cn/2012/01/%e6%90%ad%e5%bb%banginxwordpress%e8%b0%83%e8%af%95%e7%8e%af%e5%a2%83.html</link>
		<comments>http://www.vimer.cn/2012/01/%e6%90%ad%e5%bb%banginxwordpress%e8%b0%83%e8%af%95%e7%8e%af%e5%a2%83.html#comments</comments>
		<pubDate>Sun, 08 Jan 2012 13:40:47 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[MySql]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2452</guid>
		<description><![CDATA[几年之前刚玩wordpress的时候，还是用apache+wordpress，而后来虽然自己成了nginx粉，却也只是用来做nginx+python的开发，没有把nginx+php配合起来。这次趁这要搭建wordpress的调试环境，所以重新梳理了... ]]></description>
			<content:encoded><![CDATA[<p>几年之前刚玩wordpress的时候，还是用apache+wordpress，而后来虽然自己成了nginx粉，却也只是用来做nginx+python的开发，没有把nginx+php配合起来。这次趁这要搭建wordpress的调试环境，所以重新梳理了一遍。<br />
PS：网上很多盛传的版本，基本都不太准，我这里算是亲身试验了，给大家个准的<br />
PS2：这次就在windows下来搞了，其实在linux也是一样</p>
<p>OK，我们正式开始</p>
<p><b>一. php安装部署</b></p>
<ol>
<li>到<a href="http://windows.php.net/download/" target="_blank" >php windows下载页面</a>下载zip包，而不是安装包</li>
<li>解压，我是解压到 D:\program\php5</li>
<li>重命名php.ini-production为php.ini</li>
<li>修改php.ini</li>
<p>    将如下代码去掉注释来支持mysql</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="conf" style="font-family:monospace;">extension=php_mysql.dll</pre></td></tr></table></div>

<p>    将如下代码去掉注释，来指明ext的路径</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="conf" style="font-family:monospace;">extension_dir = &quot;ext&quot;</pre></td></tr></table></div>

</ol>
<p><b>二. mysql安装部署</b></p>
<ol>
<li>到<a href="http://www.mysql.com/downloads/mysql/" target="_blank" >http://www.mysql.com/downloads/mysql/</a>下载windows版MySQL Community Server</li>
<li>安装，并启动服务（默认是随机启动，否则请 net start mysql）</li>
</ol>
<p><b>三. nginx安装部署</b></p>
<ol>
<li>到 <a href="http://www.nginx.org/" target="_blank" >http://www.nginx.org/</a>下载最新的nginx</li>
<li>解压，我是解压到 D:\program\nginx</li>
<li>可以新建如下三个bat脚本，可以快速的实现nginx在windows下的启动、停止、重载，放在与nginx.exe的统计目录即可</li>
<p>    start.bat</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="bat" style="font-family:monospace;">%~d0
cd &quot;%~dp0&quot;
start nginx.exe</pre></td></tr></table></div>

<p>    stop.bat</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="bat" style="font-family:monospace;">%~d0
cd &quot;%~dp0&quot;
start nginx.exe -s stop</pre></td></tr></table></div>

<p>    reloat.bat</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="bat" style="font-family:monospace;">%~d0
cd &quot;%~dp0&quot;
start nginx.exe -s reload</pre></td></tr></table></div>

</ol>
<p><b>四. wordpress安装部署</b></p>
<ol>
<li>到 <a href="http://cn.wordpress.org/" target="_blank" >http://cn.wordpress.org/</a> 下载wordpress最新版 </li>
<li>解压，我是解压到D:\www\wp</li>
<li>在 D:\www\wp 目录下新建如下脚本</li>
<p>    start.bat</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="bat" style="font-family:monospace;">D:/program/php5/php-cgi.exe -b 127.0.0.1:1998 -c D:/program/php5/php.ini</pre></td></tr></table></div>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #000080;">set</span> wscriptObj = CreateObject(<span style="color: #800000;">&quot;Wscript.Shell&quot;</span>)
wscriptObj.run <span style="color: #800000;">&quot;start.bat&quot;</span>,0</pre></td></tr></table></div>

<p>    其中，start.bat可以能够启动fastcgi服务，但是会有一个dos窗口。如果用start.vbs的方式启动，就可以隐藏掉dos窗口。
</ol>
<p><b>五. 配置nginx</b></p>
<ol>
<li>修改nginx.conf，新建server配置如下</li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="conf" style="font-family:monospace;">server {
    listen       80;
    server_name  wp.qq.com;
&nbsp;
    root         D:/www/wp;
&nbsp;
    rewrite /wp-admin$ $scheme://$host$uri/ permanent;
&nbsp;
    location / {
        fastcgi_pass   127.0.0.1:1998;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
&nbsp;
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
            expires max;
            log_not_found off;
    }
}</pre></td></tr></table></div>

<p>    其中如下两项，你可能和我设置的不一样，自行修改就可以了</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="conf" style="font-family:monospace;">root         D:/www/wp;
fastcgi_pass   127.0.0.1:1998;</pre></td></tr></table></div>

<p>    而对于如下的静态化的配置，则一定要配置上，之前就是在这里调试了半天。。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="conf" style="font-family:monospace;">location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
}</pre></td></tr></table></div>

<li>重启nginx，OK！</li>
</ol>
<p>OK，访问 127.0.0.1，看下是否出现了wordpress的安装界面？哈哈，搞定！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2012/01/%e6%90%ad%e5%bb%banginxwordpress%e8%b0%83%e8%af%95%e7%8e%af%e5%a2%83.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>bottle做web开发的物理设计</title>
		<link>http://www.vimer.cn/2011/12/bottle%e5%81%9aweb%e5%bc%80%e5%8f%91%e7%9a%84%e7%89%a9%e7%90%86%e8%ae%be%e8%ae%a1.html</link>
		<comments>http://www.vimer.cn/2011/12/bottle%e5%81%9aweb%e5%bc%80%e5%8f%91%e7%9a%84%e7%89%a9%e7%90%86%e8%ae%be%e8%ae%a1.html#comments</comments>
		<pubDate>Mon, 05 Dec 2011 16:44:59 +0000</pubDate>
		<dc:creator>Dante</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[bottle.]]></category>
		<category><![CDATA[web开发]]></category>
		<category><![CDATA[物理设计]]></category>

		<guid isPermaLink="false">http://www.vimer.cn/?p=2419</guid>
		<description><![CDATA[接着回归简单，向Django说再见，继续来聊用bottle做web开发。 其实上一篇文章已经讲的比较清楚了，这一次主要从另一个角度来分享一下：物理设计 干脆直接贴出来吧： 1 2 3 4 5 6 7 8 9 10 11 12 13 14... ]]></description>
			<content:encoded><![CDATA[<p>接着<a href="http://www.vimer.cn/2011/11/%E5%9B%9E%E5%BD%92%E7%AE%80%E5%8D%95%EF%BC%8C%E5%90%91django%E8%AF%B4%E5%86%8D%E8%A7%81.html" target="_blank" >回归简单，向Django说再见</a>，继续来聊用<a href="http://bottlepy.org/" target="_blank" >bottle</a>做web开发。</p>
<p>其实上一篇文章已经讲的比较清楚了，这一次主要从另一个角度来分享一下：<b>物理设计</b></p>
<p>干脆直接贴出来吧：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><pre class="txt" style="font-family:monospace;">bottle_site_tpl/
|~conf/
|~depend/
| |+autumn/
| |+jinja2/
| |+wtforms/
| |-__init__.py
| `-bottle.py
|~log/
| `-site.log
|~module/
| |-__init__.py
| |-forms.py
| |-models.py
| |-mysession.py
| `-web_func.py
|+static/
|~views/
| `-test.html
|~web/
| |-__init__.py
| `-test.py
|-myapp.py
`-setting.py</pre></td></tr></table></div>

<p>可以看出，最外层有两个文件，分别是setting.py 和 myapp.py。<br />
setting.py（很像django吧，哈哈），顾名思义，是各种配置项，包括log目录和等级，模板目录，静态文件目录等。<br />
而myapp.py的代码如下:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> setting
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> debug, run
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> web <span style="color: #ff7700;font-weight:bold;">import</span> app
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    debug<span style="color: black;">&#40;</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    run<span style="color: black;">&#40;</span>app, host=<span style="color: #483d8b;">&quot;0.0.0.0&quot;</span>, port=<span style="color: #ff4500;">80</span>, reloader=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>相当于一个启动器，通过执行 python myapp.py 可启动整个网站。（当然，也可以和uwsgi结合）</p>
<p>接着我们进入第二级目录，从web目录开始:<br />
web目录用来存放Bottle的各个实例，构成了网站的主框架。</p>
<p>其中的__init__.py代码如下:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> Bottle
<span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> debug, run
<span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> redirect, abort, static_file
<span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> jinja2_template <span style="color: #ff7700;font-weight:bold;">as</span> template
<span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> request, response, local
<span style="color: #ff7700;font-weight:bold;">from</span> bottle <span style="color: #ff7700;font-weight:bold;">import</span> TEMPLATE_PATH
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> mysession <span style="color: #ff7700;font-weight:bold;">import</span> get_session_info, set_session_info
<span style="color: #ff7700;font-weight:bold;">from</span> mysession <span style="color: #ff7700;font-weight:bold;">import</span> deco_session_check
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> setting <span style="color: #ff7700;font-weight:bold;">import</span> CUSTOM_TPL_PATH
TEMPLATE_PATH.<span style="color: black;">insert</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, CUSTOM_TPL_PATH<span style="color: black;">&#41;</span>
&nbsp;
app = Bottle<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
app.<span style="color: black;">mount</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/test'</span>, <span style="color: #008000;">__import__</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'test'</span><span style="color: black;">&#41;</span>.<span style="color: black;">app</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    debug<span style="color: black;">&#40;</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    run<span style="color: black;">&#40;</span>app, host=<span style="color: #483d8b;">&quot;0.0.0.0&quot;</span>,reloader=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>可见 web.__init__.py 是统一管理web相关资源的入口，会mount各个模块，而对于test.py，则是各个模块对应的实现。</p>
<ul>
<li>
    depend 目录是存放各个依赖的模块，这样做会更容易管理。
    </li>
<li>
    module 是开发中较为独立的模块，比如models.py是模型，forms.py是表单等等
    </li>
<li>
    views 是模板目录
    </li>
<li>
    static 是静态文件目录
    </li>
<li>
    log 是日志目录
    </li>
</ul>
<p>OK，整个就是这样了。<br />
按照这样来做了之后，整个模块的划分就清晰了很多，可扩展性也好了很多。<br />
当然，这只是我一家之言，如果有朋友有更好的物理设计，也欢迎告知。</p>
<p>惯例，代码放在这里：<br />
<a href="http://code.google.com/p/vimercode/source/browse/#svn%2Ftrunk%2Fbottle_site_tpl" target="_blank" >http://code.google.com/p/vimercode/source/browse/#svn%2Ftrunk%2Fbottle_site_tpl</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.vimer.cn/2011/12/bottle%e5%81%9aweb%e5%bc%80%e5%8f%91%e7%9a%84%e7%89%a9%e7%90%86%e8%ae%be%e8%ae%a1.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

