自定义Web组件
一、Session
1、面向对象基础
面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ 、__delitem__、__setitem__方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo( object ): def __getitem__( self , key): print '__getitem__' ,key def __setitem__( self , key, value): print '__setitem__' ,key,value def __delitem__( self , key): print '__delitem__' ,key obj = Foo() result = obj[ 'k1' ] #obj['k2'] = 'wupeiqi' #del obj['k1'] |
2、Tornado扩展
Tornado框架中,默认执行Handler的get/post等方法之前默认会执行 initialize方法,所以可以通过自定义的方式使得所有请求在处理前执行操作...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class BaseHandler(tornado.web.RequestHandler): def initialize( self ): self .xxoo = "wupeiqi" class MainHandler(BaseHandler): def get( self ): print ( self .xxoo) self .write( 'index' ) class IndexHandler(BaseHandler): def get( self ): print ( self .xxoo) self .write( 'index' ) |
3、session
session其实就是定义在服务器端用于保存用户回话的容器,其必须依赖cookie才能实现。
#!/usr/bin/env python # -*- coding:utf-8 -*- import config from hashlib import sha1 import os import time create_session_id = lambda: sha1(bytes('%s%s' % (os.urandom(16), time.time()), encoding='utf-8')).hexdigest() class SessionFactory: @staticmethod def get_session_obj(handler): obj = None if config.SESSION_TYPE == "cache": obj = CacheSession(handler) elif config.SESSION_TYPE == "memcached": obj = MemcachedSession(handler) elif config.SESSION_TYPE == "redis": obj = RedisSession(handler) return obj class CacheSession: session_container = {} session_id = "__sessionId__" def __init__(self, handler): self.handler = handler client_random_str = handler.get_cookie(CacheSession.session_id, None) if client_random_str and client_random_str in CacheSession.session_container: self.random_str = client_random_str else: self.random_str = create_session_id() CacheSession.session_container[self.random_str] = {} expires_time = time.time() + config.SESSION_EXPIRES handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time) def __getitem__(self, key): ret = CacheSession.session_container[self.random_str].get(key, None) return ret def __setitem__(self, key, value): CacheSession.session_container[self.random_str][key] = value def __delitem__(self, key): if key in CacheSession.session_container[self.random_str]: del CacheSession.session_container[self.random_str][key] class RedisSession: def __init__(self, handler): pass class MemcachedSession: def __init__(self, handler): pass
4、分布式Session
# -*- coding: utf-8 -*- """ hash_ring ~~~~~~~~~~~~~~ Implements consistent hashing that can be used when the number of server nodes can increase or decrease (like in memcached). Consistent hashing is a scheme that provides a hash table functionality in a way that the adding or removing of one slot does not significantly change the mapping of keys to slots. More information about consistent hashing can be read in these articles: "Web Caching with Consistent Hashing": http://www8.org/w8-papers/2a-webserver/caching/paper2.html "Consistent hashing and random trees: Distributed caching protocols for relieving hot spots on the World Wide Web (1997)": http://citeseerx.ist.psu.edu/legacymapper?did=38148 Example of usage:: memcache_servers = ['192.168.0.246:11212', '192.168.0.247:11212', '192.168.0.249:11212'] ring = HashRing(memcache_servers) server = ring.get_node('my_key') :copyright: 2008 by Amir Salihefendic. :license: BSD """ import math import sys from bisect import bisect if sys.version_info >= (2, 5): import hashlib md5_constructor = hashlib.md5 else: import md5 md5_constructor = md5.new class HashRing(object): def __init__(self, nodes=None, weights=None): """`nodes` is a list of objects that have a proper __str__ representation. `weights` is dictionary that sets weights to the nodes. The default weight is that all nodes are equal. """ self.ring = dict() self._sorted_keys = [] self.nodes = nodes if not weights: weights = {} self.weights = weights self._generate_circle() def _generate_circle(self): """Generates the circle. """ total_weight = 0 for node in self.nodes: total_weight += self.weights.get(node, 1) for node in self.nodes: weight = 1 if node in self.weights: weight = self.weights.get(node) factor = math.floor((40*len(self.nodes)*weight) / total_weight) for j in range(0, int(factor)): b_key = self._hash_digest( '%s-%s' % (node, j) ) for i in range(0, 3): key = self._hash_val(b_key, lambda x: x+i*4) self.ring[key] = node self._sorted_keys.append(key) self._sorted_keys.sort() def get_node(self, string_key): """Given a string key a corresponding node in the hash ring is returned. If the hash ring is empty, `None` is returned. """ pos = self.get_node_pos(string_key) if pos is None: return None return self.ring[ self._sorted_keys[pos] ] def get_node_pos(self, string_key): """Given a string key a corresponding node in the hash ring is returned along with it's position in the ring. If the hash ring is empty, (`None`, `None`) is returned. """ if not self.ring: return None key = self.gen_key(string_key) nodes = self._sorted_keys pos = bisect(nodes, key) if pos == len(nodes): return 0 else: return pos def iterate_nodes(self, string_key, distinct=True): """Given a string key it returns the nodes as a generator that can hold the key. The generator iterates one time through the ring starting at the correct position. if `distinct` is set, then the nodes returned will be unique, i.e. no virtual copies will be returned. """ if not self.ring: yield None, None returned_values = set() def distinct_filter(value): if str(value) not in returned_values: returned_values.add(str(value)) return value pos = self.get_node_pos(string_key) for key in self._sorted_keys[pos:]: val = distinct_filter(self.ring[key]) if val: yield val for i, key in enumerate(self._sorted_keys): if i < pos: val = distinct_filter(self.ring[key]) if val: yield val def gen_key(self, key): """Given a string key it returns a long value, this long value represents a place on the hash ring. md5 is currently used because it mixes well. """ b_key = self._hash_digest(key) return self._hash_val(b_key, lambda x: x) def _hash_val(self, b_key, entry_fn): return (( b_key[entry_fn(3)] << 24) |(b_key[entry_fn(2)] << 16) |(b_key[entry_fn(1)] << 8) | b_key[entry_fn(0)] ) def _hash_digest(self, key): m = md5_constructor() m.update(key.encode('utf-8')) # return map(ord, m.digest()) # python 2 return list(m.digest()) # pyhton 3
session
二、表单(form)验证
在Web程序中往往包含大量的表单验证的工作,如:判断输入是否为空,是否符合规则。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <link href="{{static_url("commons.css")}}" rel="stylesheet" /> </head> <body> <h1>hello</h1> <form action="/index" method="post"> <p>hostname: <input type="text" name="host" /> </p> <p>ip: <input type="text" name="ip" /> </p> <p>port: <input type="text" name="port" /> </p> <p>phone: <input type="text" name="phone" /> </p> <input type="submit" /> </form> </body> </html>
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web from hashlib import sha1 import os, time import re class MainForm(object): def __init__(self): self.host = "(.*)" self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$" self.port = '(\d+)' self.phone = '^1[3|4|5|8][0-9]\d{8}$' def check_valid(self, request): form_dict = self.__dict__ for key, regular in form_dict.items(): post_value = request.get_argument(key) # 让提交的数据 和 定义的正则表达式进行匹配 ret = re.match(regular, post_value) print key,ret,post_value class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') def post(self, *args, **kwargs): obj = MainForm() result = obj.check_valid(self) self.write('ok') settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh', 'login_url': '/login' } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
由于验证规则可以代码重用,所以可以如此定义:
View Code