# Tested with Python 2.7.9, Linux & Mac OS X
importsocketimportStringIOimportsysclassWSGIServer(object):address_family=socket.AF_INETsocket_type=socket.SOCK_STREAMrequest_queue_size=1def__init__(self,server_address):# Create a listening socket
self.listen_socket=listen_socket=socket.socket(self.address_family,self.socket_type)# Allow to reuse the same address
listen_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)# Bind
listen_socket.bind(server_address)# Activate
listen_socket.listen(self.request_queue_size)# Get server host name and port
host,port=self.listen_socket.getsockname()[:2]self.server_name=socket.getfqdn(host)self.server_port=port# Return headers set by Web framework/Web application
self.headers_set=[]defset_app(self,application):self.application=applicationdefserve_forever(self):listen_socket=self.listen_socketwhileTrue:# New client connection
self.client_connection,client_address=listen_socket.accept()# Handle one request and close the client connection. Then
# loop over to wait for another client connection
self.handle_one_request()defhandle_one_request(self):self.request_data=request_data=self.client_connection.recv(1024)# Print formatted request data a la 'curl -v'
print(''.join('< {line}\n'.format(line=line)forlineinrequest_data.splitlines()))self.parse_request(request_data)# Construct environment dictionary using request data
env=self.get_environ()# It's time to call our application callable and get
# back a result that will become HTTP response body
result=self.application(env,self.start_response)# Construct a response and send it back to the client
self.finish_response(result)defparse_request(self,text):request_line=text.splitlines()[0]request_line=request_line.rstrip('\r\n')# Break down the request line into components
(self.request_method,# GET
self.path,# /hello
self.request_version# HTTP/1.1
)=request_line.split()defget_environ(self):env={}# The following code snippet does not follow PEP8 conventions
# but it's formatted the way it is for demonstration purposes
# to emphasize the required variables and their values
#
# Required WSGI variables
env['wsgi.version']=(1,0)env['wsgi.url_scheme']='http'env['wsgi.input']=StringIO.StringIO(self.request_data)env['wsgi.errors']=sys.stderrenv['wsgi.multithread']=Falseenv['wsgi.multiprocess']=Falseenv['wsgi.run_once']=False# Required CGI variables
env['REQUEST_METHOD']=self.request_method# GET
env['PATH_INFO']=self.path# /hello
env['SERVER_NAME']=self.server_name# localhost
env['SERVER_PORT']=str(self.server_port)# 8888
returnenvdefstart_response(self,status,response_headers,exc_info=None):# Add necessary server headers
server_headers=[('Date','Tue, 31 Mar 2015 12:54:48 GMT'),('Server','WSGIServer 0.2'),]self.headers_set=[status,response_headers+server_headers]# To adhere to WSGI specification the start_response must return
# a 'write' callable. We simplicity's sake we'll ignore that detail
# for now.
# return self.finish_response
deffinish_response(self,result):try:status,response_headers=self.headers_setresponse='HTTP/1.1 {status}\r\n'.format(status=status)forheaderinresponse_headers:response+='{0}: {1}\r\n'.format(*header)response+='\r\n'fordatainresult:response+=data# Print formatted response data a la 'curl -v'
print(''.join('> {line}\n'.format(line=line)forlineinresponse.splitlines()))self.client_connection.sendall(response)finally:self.client_connection.close()SERVER_ADDRESS=(HOST,PORT)='',8888defmake_server(server_address,application):server=WSGIServer(server_address)server.set_app(application)returnserverif__name__=='__main__':iflen(sys.argv)<2:sys.exit('Provide a WSGI application object as module:callable')app_path=sys.argv[1]module,application=app_path.split(':')module=__import__(module)application=getattr(module,application)httpd=make_server(SERVER_ADDRESS,application)print('WSGIServer: Serving HTTP on port {port} ...\n'.format(port=PORT))httpd.serve_forever()
Python WSGI框架
#应用一
frompyramid.configimportConfiguratorfrompyramid.responseimportResponsedefhello_world(request):returnResponse('Hello world from Pyramid!\n',content_type='text/plain',)config=Configurator()config.add_route('hello','/hello')config.add_view(hello_world,route_name='hello')app=config.make_wsgi_app()
#应用二
fromflaskimportFlaskfromflaskimportResponseflask_app=Flask('flaskapp')@flask_app.route('/hello')defhello_world():returnResponse('Hello world from Flask!\n',mimetype='text/plain')app=flask_app.wsgi_app
#vim wsgiapp.py
defapp(environ,start_response):"""A barebones WSGI application.
This is a starting point for your own Web framework :)
"""status='200 OK'response_headers=[('Content-Type','text/plain')]start_response(status,response_headers)return['Hello world from a simple WSGI application!\n']