280 likes | 472 Views
一层一层说网站. PYTHON WSGI简介 及 常用中间件. 张沈鹏 42qu.com作者. 著名的洋葱. 请求(Request)的构成. 1. 网址: 用户输入 2. COOKIE: 网站设置 3. 其他HTTP头: 浏览器. GET /@zsp HTTP/1.1 Host: kanrss.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
E N D
一层一层说网站 PYTHON WSGI简介 及 常用中间件 张沈鹏 42qu.com作者
请求(Request)的构成 1. 网址: 用户输入 2. COOKIE: 网站设置 3. 其他HTTP头: 浏览器 GET /@zsp HTTP/1.1 Host: kanrss.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Cookie: B=kwyP64YM; __utma=5797929.751142743.1280312171.1280312171.1280312171.1; __utmb=5797929.5.10.1280312171; __utmz=5797929.1280312171.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); Hm_lvt_fc05ad55c7dcadfd714baf512f9146b3=1280312172072; Hm_lpvt_fc05ad55c7dcadfd714baf512f9146b3=1280312287556; __utmc=5797929 Cache-Control: max-age=0
响应Response 构成 HTTP/1.1 200 OK Server: nginx/0.7.65 Date: Wed, 28 Jul 2010 10:24:29 GMT Content-Type: text/html; charset=UTF-8 Connection: keep-alive Content-Encoding: gzip Content-Length: 6241 <!doctype html> <head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><link href="http://stdyun.net/css/a6hYw~g.css" rel="stylesheet" type="text/css"><script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script src="/js/~QFhCQ~s.js"></script><title>张沈鹏(KanRSS.com/码农 行业:互联网)</title></head><body><div id="h"><div class="C"><div id="hnav"><a href="/">首页</a> <a href="/auth/apply">注册</a> <a href="/auth/login">登录</a></div></div></div><div class="C"> <div class="at"> <div class="atimg"> <a href="/auth/login?path=/%40zsp" class="bwc" onclick="return poplogin('/@zsp')"> 追随 </a><div><a href="/@zsp"><img class="img9
Request 常见洋葱核结构 简化图 WSGI Server Nginx DNS Request Parser URL Route Template Control Model
CGI -> WSGI http://www.python.org/dev/peps/pep-0333/ def run_with_cgi(application): environ = dict(os.environ.items()) environ['wsgi.input'] = sys.stdin environ['wsgi.errors'] = sys.stderr environ['wsgi.version'] = (1,0) environ['wsgi.multithread'] = False environ['wsgi.multiprocess'] = True environ['wsgi.run_once'] = True if environ.get('HTTPS','off') in ('on','1'): environ['wsgi.url_scheme'] = 'https' else: environ['wsgi.url_scheme'] = 'http' .................
os.environ http://angeloce.javaeye.com/blog/523242 REQUEST_METHOD -> GET 或 POST PATH_INFO -> /xxx/xx QUERY_STRING -> 在"?"后面的请求URL部分.可以为空 HTTP_ Variables -> 与客户端支持的HTTP请求头一致的变量.(也就是以"HTTP_"开头命名的变量.)这些变量是否出现都要与HTTP请求头中的变量保持一致. ...............
WSGI Server import tornado.wsgi import tornado.httpserver import tornado.ioloop def WSGIServer(port, application): container = tornado.wsgi.WSGIContainer(application) http_server = tornado.httpserver.HTTPServer(container) http_server.listen(port) tornado.ioloop.IOLoop.instance().start()
洋葱核 1. environ 2. start_response 3. return ['xxxx'] def app(environ, start_response): status = '200 OK' response_headers = [ ('Content-type','text/plain'), ] start_response(status, response_headers) return ['Hello']
Request Parser • yaro - Yet Another Request Object • http://lukearno.com/projects/yaro/ 1. 简化environ的访问 environ['QUERY_STRING'] hl=zh-CN&source=hp&q=python&aq=f&aqi=&aql=&oq=&gs_rfai= -> req.query = { "hl":"zh-CN", "source":"hp", ....
Request Parser 2. 封装 start_response status = '200 OK' response_headers = [ ('Content-type','text/plain'), ] start_response(status, response_headers) return ['Hello'] -> from yaro import Yaro @Yaro def hello_world(req): return "Hello World!" 当然, 也被封装一些状态码 yaro.Request.redirect("/xxx/xxx/xxx") 301 status
URL Route URL -> Python Function http://kanrss.com/at/cloudwu/t/1270561 -> mysite/ctrl/at/__init__.py @route_render_func def t(id=None): owner = request.owner ...
URL Route 常用方式 正则匹配 application = tornado.web.Application([ (r"/", MainHandler), (r"/story/([0-9]+)", StoryHandler), ]) class StoryHandler(tornado.web.RequestHandler): def get(self, story_id): self.write("You requested the story " + story_id)
Url Route -- 文件路径映射 http://mayoufour.googlecode.com/svn/trunk/mypylib/mypy/urlroute.py 创意衍生自 Quixote 查找映射的函数 = { 路径1 :{ 路径2:{ 模块名 : 函数名称 } } } "/at/cloudwu/t/1270561".split("") -> 'at', 'cloudwu', //被当作 at._access(id)函数的参数吃掉 't', '1270561', //被当作 at.t(id)函数的参数吃掉
Model 表 的 映射 • CREATE TABLE `user` ( • `id` int(10) unsigned NOT NULL AUTO_INCREMENT, • `name` varbinary(24) NOT NULL, • `url` varbinary(60) DEFAULT NULL, • `ver` tinyint(3) unsigned NOT NULL DEFAULT '0', • `state` tinyint(3) unsigned NOT NULL DEFAULT '40', • PRIMARY KEY (`id`), • UNIQUE KEY `url` (`url`), • KEY `state` (`state`), • KEY `name` (`name`) • ) -> user.name , user.state
Model 表的行为 ban_user -> 设置user.state + 删除user_session使其退出登录 表 与的 表 互动 table user <=> table user follow -> def follower_by_user_id(user_id): ....
Control 1. 提交表单的数据格式效验 2. 从Model获取页面需要的数据 3. 权限不对的时候 给出错误提示 if not user.can_admin(group): G.error = "你没有权限管理该小组" -- 传递变量 --> 模板
模板 %for i in items: <item> <title>${i['title']}</title> <link>${i['link']}</link> <dc:creator>${i['author']}</dc:creator> <description><![CDATA[${i['desc']}]]></description> <pubDate>${format_rfc822_date(i['pubdate'])}</pubDate> <guid isPermaLink="true">${i['link']}</guid> </item> %endfor
被遗忘缓存 Model -> memcache -> Control 1.缓存id列表 mc_book_section_id_ordered_can_view = McCacheA("BookSectionIdOrderedCanView:%s") @mc_book_section_id_ordered_can_view("{id}") def book_section_id_ordered_can_view(id): book_list = book_section_ordered(id) return [ i.id for i in book_list if i.can_view ] 2.缓存对象 user_list = User.mc_get_list(user_id_list) 需要在有改动的时候手工清理
被遗忘缓存 Template -> memcache -> WSGI Server 页面局部的memcache缓存 <%def name="mycomp" cached="True" cache_timeout="300" cache_type="memcached"> other text </%def> 节省取数据 + 模板的开销 一般自动超时失效
被遗忘缓存 WSGI Server -> Nginx Proxy Cache -> ... server_name rss_group.kanrss.com; location ~ ^/(\d+)$ { proxy_pass http://kanrss/vgroup/$1/rss_feed; proxy_cache KFS; proxy_cache_valid 200 304 301 302 30m; proxy_cache_valid any 1m; proxy_cache_key "$host$request_uri"; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } 比如 RSS (firefox会检查收藏夹中的rss更新 -> 压力不小) 比如 一些不经常变的Ajax响应(比如搜索的自动完成?)
还没有说的... • 辅助开发 • WEB前端优化 • 异步运行 • 长连接 • OpenID .... ... ....
更多更多... • Profile?
更多更多... • Debug?
更多更多... • Auto Restart ? https://mayoufour.googlecode.com/svn/trunk/mypylib/mypy/reloader.py https://mayoufour.googlecode.com/svn/trunk/mypylib/mypy/reload_server.py
区 42 qu.com 找到给你答案的人
import sys sys.exit()