In Python web development, the server program can be divided into 2 parts:
Server program (used to receive and organize requests sent by the client)
Application program (processing requests passed by the server program)
In developing applications When programming, we encapsulate commonly used functions into various frameworks, such as Flask, Django, and Tornado (using a certain framework for web development is equivalent to developing server-side applications and processing background logic)
However, server programs and Only applications that work together can provide services to users, and different applications (different frameworks) will have different functions and functions. At this time, we need a standard so that both server programs and applications can support this standard. Then, the two can cooperate well. WSGI: wsgi is a standard for python web development, similar to a protocol. It is a convention between the server program and the application program, which stipulates the interfaces and functions used by each so that the two can cooperate with each other
Part of the provisions of the WSGI application
The application is a callable object
There are three types of callable objects :
A function
A class must implement the __call__() method
An instance of a class
This object receives two parameters
class application:
pass
The callable object needs to return an iterable value. Take the callable object as a class as an example:
class application:
def __call__(self, environ, start_response): return [xxx]
Part of the provisions of the WSGI server program
The server program needs to call the application
DEF RUN (Application): #d
environment Environment = {} #Set parameter
DEF Start_response (xxx): #Set parameter
Pass
Result = Application (ENVIRON, Start_response) # Call the application _ _call__ function (here the application is a class)
def write(data):
pass
def data in result: #Iterative access
’s ‐ ‐ ‐ ‐ Parameters required by the program
2. Call the application
3. Iteratively access the return result of the application and pass it to the client
Middleware
For the application program, the middleware is the server program. The middleware needs to be disguised as the server program, accept and call the application program
The server program obtains the URL requested by the client and needs to hand the URL to different functions for processing. This function can be implemented using middleware:
def urlrouting(url_app_mapping):
def midware_app(environ, start_response): #The function is callable, contains 2 parameters, and returns an iterable value url = environ['PATH_INFO']
use using url ’s ’ through through through through ’s ’’s ’ through ’ s through ‐ to ‐‐‐ ‐‐‐‐ and
to return an iterable value. #Call application Program u Return Result
Return Midware_app
function Midware_app is Middleware:
On the one hand, the MidWare_app function sets the variables required by the application and calls the application. So for the application, it is a server program
On the other hand, the midware_app function is a callable object that receives two parameters, and the callable object returns an iterable value. So for the server program, it is an application
The logic of writing middleware (middleware):
1. Middleware needs to be disguised as an application—> Requirements for WSGI applications—> 1. Callable 2. Two Parameters 3. Return an iterable value
2. The middleware needs to disguise itself as a server program—> WSGI server program requirements—> Call the application
We need to understand the variable environ. In WSGI, the application requires two parameters: environ and start_response. These two parameters need to be set before the server program calls the application. Among them, start_response is usually a callable method, and environ is a dictionary, which is defined in CGI. Check the CGI document The Common Gateway Interface Specification to find the definition of environ.
The following are the parameters in environ:
AUTH_TYPE
CONTENT_LENGTH #The Content-Length part of the HTTP request
CONTENT_TYPE #The Content-Tpye part of the HTTP request
GATEWAY_INTERFACE
HTTP_* #Contains a series of variables, such as HTTP_HOST, HTTP_ACCEPT, etc.
PATH_INFO #The remaining part of the URL path except the initial part is used to find the corresponding application object. If the requested path is the root path, this value is an empty string
PATH_TRANSLATED
QUERY_STRING #In the URL path? The following part
REMOTE_ADDR
REMOTE_HOST
REMOTE_IDENT
REMOTE_USER
REQUEST_METHOD #HTTP request method, such as "GET", "POST"
SCRipT_NAME #The application object corresponding to the starting part of the URL path, if the application object corresponds to the root of the server, Then this value can be an empty string
SERVER_NAME
SERVER_PORT
SERVER_PROTOCOL #Protocol requested by the client (HTTP/1.1 HTTP/1.0)
SERVER_SOFTWARE
Example: http://localhost:5000/aaa?666, the variable value is :
REQUEST_METHOD='GET'
SCRIPT_NAME=''
SERVER_NAME='localhost'
SERVER_PORT='5000'
PATH_INFO='/aaa'
QUERY_STRING='666'
SERVER_PROTOCOL='HTTP/1.1'
CONTENT_TYPE=' text/plain'
CONTEN_LENGTH=''
HTTP_HOST = 'localhost:8000'
HTTP_ACCEPT = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q= 0.8'
HTTP_ACCEPT_ENCODING = 'gzip,deflate,sdch'
HTTP_ACCEPT_LANGUAGE = 'en-US,en;q=0.8,zh;q=0.6,zh-CN;q=0.4,zh-TW;q=0.2'
HTTP_CONNECTION = 'keep-alive'
HTTP_USER_AGENT = 'Mozilla/5.0 (X11; linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36'
For start_response() function:
start_response is HTTP The beginning of the response, its form is: start_response(status, response_headers, exc_info=None)
status represents the HTTP status code, such as 200 OK
response_headers is a list, and the list element is a tuple: (header_name, header_value)
exc_info is optional Parameter, when an error occurs during request processing, this parameter will be set, and start_response will be called at the same time. Let’s take an example from the official werkzeug document. I slightly improved it for analysis (it is recommended to read this paragraph after reading wsgi.py second See part of the SharedDataMiddleware class again):
def __init__(self, config):
self.redis = redis.Redis(config['redis_host'], config['redis_port'])
def dispatch_request(self, request):
return Response('Hello World!') #Initialize the Response class
def wsgi_app(self, environ, start_response):
request = Request(environ)
res ponse = self.dispatch_request(request ) #Response type is the response class
Print ('%%%%%owventage%%%%owventage. Response's __call__ function is the application, returning the iteration object
def __call__(self, environ, start_response):
print(self.wsgi_app)
print('erghrgheoghegoierge')
return self. wsgi_app(environ, start_response)
EDef Create_app (redis_host = 'localhost', redis_port = 6379, with_Static = TRUE):
app = shortly ({
'redis_host': redis_host,
'redis_p Ort ': Redis_port
})
if with_static:
Print (' yes')
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
yes'
return app
#Start the local server
if __name__ == '__main__':
from werkzeug.serving import run_simple
app = create_app() #Create an instance of the application
run_simple('127.0.0.1', 5000, app, use_debugger =True, use_reloader=True)
We look at the source code of Response (Response inherits BaseResponse, just look at the source code of BaseResponse) and we can know: the value returned by the function dispatch_request() is the constructor of Request, that is, a Response class is returned. In the function wsgi_app(), request The value type is Response, so the return value response(environ, start_response) of wsgi_app() actually calls the __call__() function of the Response class.
After looking at the source code, we can find that __call__() is a WSGI application!
When running this program:
22222222222222222
yes
333333333333333
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
2222222 2222222222
yes
33333333333333333
Let’s not worry about why it was read twice.
When we open this web page, the output of the console is:
erghrgheoghegoierge
%%%%%%%%%%%%%%%%%%%%%%%%% #Indicates that the content in the original wsgi_app function is executed!
127.0.0.1 - - [22/May/2015 21:01:25] "GET / HTTP/1.1" 200 -
You can notice that in this example, the app.wsgi_app method has become a SharedDataMiddleware Class instance, I am very curious about why wsgi_pp still executes the content in the original wsgi_app after the server passes environ and start_response to the app?
When we access the host address, the server program accepts the user request, and then passes environ and start_response to the application app. The app will execute the __call__ function, in which the app.wsgi_app function will be executed. Then wsgi_app will execute the __call__() function of ShareDataMiddleware. Here we need to look at the source code of __call__() of the SharedDataMiddleware class. Looking at the source code, we can find that since the user did not request a static file, return self.app(environ, start_response) will be executed. In this example, we can see that in create_app(), the ShareDataMiddleware application we defined is app.wsgi_app, so what is returned here is the original wsgi_app function! So of course the original function will be executed~
At the same time, we can also put a file in the static folder, and then try accessing it: 127.0.0.1/static/filename, and you can see the file now!
Through this example, we can have a deeper understanding of the role of Middleware:
start_response), and do certain processing, and then Pass the parts that need to be processed by the application to the application for processing
-wsgi.version to be processed by the application,
Indicates the mode of the url, such as "https" or "http" Â wsgi.erros .multithread
If the application object can be called simultaneously by another thread in the same process, this value is True
wsgi.multiprocess
If the application object can be called simultaneously by another process, this value is True
wsgi.run_once
If The server hopes that the application object will only be called once in the process that contains it, then this value is True