#文件名为 " ok7.py "
import os,os.path
print __name__
print __file__
print os.path.abspath(__file__)
print os.path.dirname(os.path.abspath(__file__))
print os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
>>> u'中'
u'\u4e2d'
所以 u '中' = u ' \u4e2d ',只不过一个是计算机的存储形式,一个是计算机的显示形式。Unicode和 utf - 8 之间用encode和decode方法相互转化。
>>> import urllib
>>> print urllib.quote("http://neeao.com/index.php?id=1")
http%3A//neeao.com/index.php%3Fid%3D1
这样在使用urllib.urlopen打开编码后的网址的时候,就会报错了。
>>> print urllib.quote("http://neeao.com/index.php?id=1",":?=/")
http://neeao.com/index.php?id=1
这下就好了。
所有的CGI程序都接收以下的环境变量,这些变量在CGI程序中发挥了重要的作用:
变量名 | 描述 |
---|---|
CONTENT_TYPE | 这个环境变量的值指示所传递来的信息的MIME类型。目前,环境变量CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示数据来自于HTML表单。 |
CONTENT_LENGTH | 如果服务器与CGI程序信息的传递方式是POST,这个环境变量即使从标准输入STDIN中可以读到的有效数据的字节数。这个环境变量在读取所输入的数据时必须使用。 |
HTTP_COOKIE | 客户机内的 COOKIE 内容。 |
HTTP_USER_AGENT | 提供包含了版本数或其他专有数据的客户浏览器信息。 |
PATH_INFO | 这个环境变量的值表示紧接在CGI程序名之后的其他路径信息。它常常作为CGI程序的参数出现。 |
QUERY_STRING | 如果服务器与CGI程序信息的传递方式是GET,这个环境变量的值即使所传递的信息。这个信息经跟在CGI程序名的后面,两者中间用一个问号'?'分隔。 |
REMOTE_ADDR | 这个环境变量的值是发送请求的客户机的IP地址,例如上面的192.168.1.67。这个值总是存在的。而且它是Web客户机需要提供给Web服务器的唯一标识,可以在CGI程序中用它来区分不同的Web客户机。 |
REMOTE_HOST | 这个环境变量的值包含发送CGI请求的客户机的主机名。如果不支持你想查询,则无需定义此环境变量。 |
REQUEST_METHOD | 提供脚本被调用的方法。对于使用 HTTP/1.0 协议的脚本,仅 GET 和 POST 有意义。 |
SCRIPT_FILENAME | CGI脚本的完整路径 |
SCRIPT_NAME | CGI脚本的的名称 |
SERVER_NAME | 这是你的 WEB 服务器的主机名、别名或IP地址。 |
SERVER_SOFTWARE | 这个环境变量的值包含了调用CGI程序的HTTP服务器的名称和版本号。例如,上面的值为Apache/2.2.14(Unix) |
#coding=utf-8
#!/usr/bin/python
import cgi, os
import cgitb; cgitb.enable()
form = cgi.FieldStorage()
# 获取文件名
fileitem = form['filename']
# 检测文件是否上传
if fileitem.filename:
# 设置文件路径
fn = os.path.basename(fileitem.filename)
open('/tmp/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
print """\
Content-Type: text/html\n
%s
""" % (message,)
# -*- coding:utf-8 -*-
import functools
def log(path):
def wrapper(func):
func.__bbbb__ = path
return func #wrapper的返回值(执行结果)
return wrapper #log函数的返回值(执行结果)
@log('x')
def now():
return 'hello'
print now.__bbbb__
# -*- coding:utf-8 -*-
import functools
def log(path):
def wrapper(func):
func.__bbbb__ = path
return func()
return wrapper
@log('x')
def now():
return 'hello'
print now.__bbbb__
得到:
@log('x')
def now():
return 'hello'
相当于执行log( ' x ' )( now ),首先log( ' x ' )返回wrapper闭包(函数),同时' x ' 作为参数传递给wrapper,得到的是
wrapper( now ),这是直接执行wrapper函数啊!
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
@log('x')
def now():
return 'hello'
用now()函数调用包装函数log后,now就不再指代原函数,而是指代
now==log('x')(now)=decorator(now),即执行decorator()函数的结果——返回的wrapper函数,也就是说now现在指代wrapper函数。现在验证一下:
def view(path):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
r= func(*args, **kw)
if isinstance(r, dict):
logging.info('return Template')
return Template(path,**r) #wrapper函数的返回值
raise ValueError('Expect return a dict when using @view() decorator.')
return wrapper #decorator函数的返回值
return decorator #view函数的返回值
def post(path):
def _decorator(func):
func.__web_route__ = path
func.__web_method__ = 'POST'
return func
return _decorator
@view('test/view.html')
@post('/post/:id')
def testpost():
return dict(a=1)
print testpost.__web_route__
print testpost.__web_method__
# -*- coding: utf-8 -*-
import logging
from transwarp.web import get, view
from models import User, Blog, Comment
@view('test_users.html')
@get('/')
def test_users():
users = User.find_all()
return dict(users=users)
app = Flask(__name__)
wsgiapp.py就是调用Flask框架的PY文件(也就是app = Flask(__name__)脚本语句所在的文件),那么__name__等于wsgiapp,其所在的目录就是web应用的根目录。
而模板文件的目录就是templates,很容易根据__name__就找到这一目录以及其下的HTML文件共模板使用。其他的模块也容易找到并导入。
实际上,Web服务器使用WSGI协议,把接收自浏览器客户端的所有请求都交给这个程序实例( object)处理,实际上使用的是这个实例拥有的方法(route()就是app实例的URL mapping方法)。
@app.route('/', methods=['GET', 'POST'])
def home():
return '<h1>Homeh1>'
服务器并不知道什么请求要用什么函数处理,它只是把所有的请求通过WSGI interface 后都交给framework或WSGI application来处理。
那么怎样才能把从浏览器来的HTTP请求都正确的处理呢,这正是我们编写处理函数(URL映射函数)的初衷。
如上例,就是“GET / HTTP/1.1”的HTTP请求的处理函数。你可能也发现了,每一个HTTP请求都务必有一个对应的处理函数,否则浏览器端的请求就会显示“ 404 not found ” . ——对请求的处理是遍历的,这是我们使用服务器端脚本语言如PHP,python等编写脚本的目的!
那么Web框架要做的工作是什么呢?
1. 将请求的 URL 映射到处理它的代码上;
2. 动态地构造请求的 HTML 返回给客户端——HTML 中带有计算得到的值或者从数据库中取出来的信息。
试想如果不使用Web框架我们要怎么做?
答:编写庞杂的wsgi application传递给名为 wsgiref 的WSGI server(符合WSGI协议标准的服务器)调用。
def application(environ, start_response):
method = environ['REQUEST_METHOD']
path = environ['PATH_INFO']
if method=='GET' and path=='/':
return handle_home(environ, start_response)
if method=='POST' and path='/signin':
return handle_signin(environ, start_response)
...
很显然我们手动拆分HTTP请求参数environ(WSGI server给的),提取出我们想要的信息,然后根据这些信息与很多的“ if ”匹配,“ 定位 ”到精确的处理函数对HTTP请求进行具体的处理事务。
使用了框架之后呢?省略了这个拆分参数和精确“定位”的步骤,我们要做的仅仅是编写URL处理函数即可——什么样的URL请求用什么样的处理函数,
编写处理函数的唯一目的是“注册”—— 即让浏览器客户端URL请求有处可寻处理函数(因为已注册的URL和相应的处理函数是绑定的——通过@decorator)。浏览器客户端URL请求匹配到了注册的URL,就是找到了相应的处理函数。
注册能处理的所有URL,未注册的自然就是非法URL——浏览器请求这样的URL时,服务器将返回错误!
框架是怎么拆分参数的:框架同样接收environ参数作为request线程级变量,通过request获取精确的参数信息。
既然拆分参数的活交给框架来做,用户再用拆分的参数来定位处理函数就毫无意义了,那么怎样办呢?
框架是如何做到精确定位的:框架内部消化拆分后的参数(比如浏览器客户端URL请求路径参数)。Flask在此之前已经通过Python的装饰器@decorator在内部自动地把注册的URL和处理函数给关联起来——根据URL来调用相应的处理函数。
至于匹配方法,一般就是遍历,直到在注册的URL中找到第一个匹配的(正则匹配),然后调用这个注册的URL对应的处理函数(用@decorator绑定的)。
When the request passes down the middleware, the incoming URL gets parsed in the RoutesMiddleware, and if it matches a URL (See URL Configuration), the information about the controller that should be called is put into the environ dict for use by PylonsApp.
The PylonsApp then attempts to find a controller in the controllers directory that matches the name of the controller, and searches for a class inside it by a similar scheme (controller name + ‘Controller’, ie, HelloController). Upon finding a controller, its then called like any other WSGI application using the same WSGI interface that PylonsApp was called with.
New in version 1.0: Controller name can also be a dotted path to the module / callable that should be imported and called. For example, to use a controller named ‘Foo’ that is in the ‘bar.controllers’ package, the controller name would be bar.controllers:Foo.
This is why the BaseController that resides in a project’s lib/base.py module inherits from WSGIController and has a __call__ method that takes the environ and start_response. The WSGIController locates a method in the class that corresponds to the action that Routes found, calls it, and returns the response completing the request.
Response时最先调用的是PylonsApp,Request 阶段的PylonsApp和Response阶段的PylonsApp不是一回事,前者接受来自Request 阶段的中间层RoutesMiddleware解析得到的URL信息(存储在environ dict中),根据URL信息得到相应的处理函数的信息存储在environ dict中,后者就要根据匹配好的处理函数的信息具体去controllers directory中找处理函数了(同时搜寻该处理函数中的一个类,类的名字是controller name + ‘Controller’)。找到之后就执行该处理函数WSGI application(按照WSGI接口标准调用),执行结果是an iterable (valid PEP 333 WSGI response), which is then sent back as the response.。
所有的处理函数(controller)都继承自BaseController,而lib/base.py模块里面的BaseController类继承自 WSGIController,且有一个__call__方法(参数是environ and start_response),WSGIController 找到一个和Routes匹配的动作相一致的方法(在__call__( )方法里面找),然后调用这个方法完成响应请求的工作。并且,In the event that an action is not found to handle the request, the Controller will raise an “Action Not Found” error if in debug mode, otherwise a 404 Not Found error will be returned.