Django 的請求對象WSGIRequest
Django的WSGIRequest
類
class WSGIRequest(HttpRequest):
def __init__(self, environ):
script_name = get_script_name(environ)
path_info = get_path_info(environ)
if not path_info:
path_info = '/'
self.environ = environ
self.path_info = path_info
self.path = '%s/%s' % (script_name.rstrip('/'),
path_info.replace('/', '', 1))
self.META = environ
self.META['PATH_INFO'] = path_info
self.META['SCRIPT_NAME'] = script_name
self.method = environ['REQUEST_METHOD'].upper()
self.content_type, self.content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
...
self._post_parse_error = False
...
self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
self._read_started = False
self.resolver_match = None
def _get_scheme(self):
return self.environ.get('wsgi.url_scheme')
# 在視圖函數(shù)中調(diào)用request.GET時才會真正的把environ中的wsgi.input對象中的響應(yīng)報文的請求參數(shù)給返回出來榕酒,然后保存在request實例屬性GET中胚膊,下次再取參數(shù)的時候就會直接從request.__dict__['GET']得到GET請求的參數(shù)
@cached_property
def GET(self):
# The WSGI spec says 'QUERY_STRING' may be absent.
raw_query_string = get_bytes_from_wsgi(self.environ, 'QUERY_STRING', '')
return QueryDict(raw_query_string, encoding=self._encoding)
def _get_post(self):
if not hasattr(self, '_post'):
self._load_post_and_files()
return self._post
def _set_post(self, post):
self._post = post
@cached_property
def COOKIES(self):
raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '')
return parse_cookie(raw_cookie)
@property
def FILES(self):
if not hasattr(self, '_files'):
self._load_post_and_files()
return self._files
POST = property(_get_post, _set_post)
GET
,POST
想鹰, COOKIES
紊婉, FILES
這幾個是非數(shù)據(jù)屬性描述符,在request被實例化出來的時候并不是request的實例屬性辑舷,而是在request.GET/POST/COOKIES/FILES時才去實際把這些請求參數(shù)或者cookie或者上傳的文件 從wsgi.input中讀取出來封裝成QueryDict
和MultiValueDict
類型的實例對象肩榕,同時會把這些QueryDict和MultiValueDict對象保存在request的實例屬性中,下次再調(diào)用request.GET/POST/COOKIES/FILES時就直接從request.__dict__
中取出即可惩妇。
本質(zhì)上是一種懶加載機制+緩存的機制株汉,只有當(dāng)用到的時候才去真正執(zhí)行取參數(shù)的操作,然后再把取得參數(shù)結(jié)果保存在request對象的實例屬性中歌殃。
django的application對象
class WSGIHandler(base.BaseHandler):
# WSGIRequest類是django自己提供的請求類乔妈,實例化之后就是request對象
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 加載中間件實例到內(nèi)存中,此時中間件實例的各種方法已經(jīng)被包裹在 _get_response() 方法的前后了
self.load_middleware()
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ)
# 實例化WSGIRequest氓皱,得到request對象路召,request對象中此時并沒有session屬性,而是在中間件加載后波材,
# 請求進(jìn)入session中間件時股淡,在session中間件的process_request()方法中動態(tài)添加的session屬性
request = self.request_class(environ)
response = self.get_response(request)
response._handler_class = self.__class__
status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = list(response.items())
for c in response.cookies.values():
response_headers.append(('Set-Cookie', c.output(header='')))
start_response(status, response_headers)
if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
response = environ['wsgi.file_wrapper'](response.file_to_stream)
return response
對于Web框架來說,它負(fù)責(zé)把environ
中的wsgi.input
中內(nèi)容進(jìn)行解析廷区,因為wsgi.input
這個對象中含有客戶端發(fā)送過來的HTTP請求報文唯灵,解析了請求報文就可以拿到客戶端傳遞的參數(shù)信息已經(jīng)文件等。然后把這些有用的參數(shù)都保存在request對象的實例屬性中隙轻。
對于Web服務(wù)器來說埠帕,它負(fù)責(zé)把接受客戶端的連接垢揩,然后把客戶端發(fā)送的http報文封裝到envion的wsgi.input
字段中,然后把這個environ
和一個回調(diào)函數(shù)start_response
傳入到web框架的入口application中敛瓷,然后調(diào)用application(environ, start_response)
返回一個response對象叁巨,最后再把取出response對象中的數(shù)據(jù),構(gòu)造成HTTP響應(yīng)報文發(fā)送到客戶端呐籽。