什麼是Web框架html
下面圖來自網上:python
pep-3333建議在Web服務器和Web應用程序/Web框架之家創建一種簡單統一的接口規範, 即Python Web服務器網關接口(簡稱WSGI)。以確保Web應用程序在不一樣的Web服務器之間具備可移植性。web
代碼部分參考的是手擼個簡單的 python web 框架教程, 我以爲這個python童鞋講的挺好。flask
# wsgi_demo.py
import pprint
# 導入python內置的wsgi server
from wsgiref.simple_server import make_server
def application(environ, start_response):
""" :param environ: 包含一些特定的WSGI環境信息的字典, 由WSGI服務器提供 :param start_response: 生成WSGI響應的回掉函數, 接受兩個必要的位置參數和一個可選參數。status,response_headers和 exc_info :return: 響應體的的迭代器 """
pprint.pprint(environ)
status = '200 ok'
response_headers = [('Content-type', 'text/html;charset=utf8')]
start_response(status, response_headers)
return ['<h1>Hello, web!</h1>'.encode()]
if __name__ == '__main__':
httpd = make_server('0.0.0.0', 5000, application)
httpd.serve_forever()
複製代碼
經過命令行跑起這個server.bash
python wsgi_demo.py
複製代碼
經過另一個命令行使用curl連接:服務器
~$ curl http://0.0.0.0:5000/
<h1>Hello, web!</h1>
複製代碼
environ字典被用來包含這些CGI環境變量。 關於理解CGI/WSGI/uWSGI能夠看看這個解釋tornado cgi wsgi uwsgi之間的關係?app
1. REQUEST_METHOD
HTTP的請求方式,好比 "GET" 或者 "POST"。這個參數永遠不多是空字符串,故必須指定。
2. PATH_INFO
URL請求中‘路徑’(‘path’)的其他部分,指定請求的目標在應用程序內部的虛擬位置。若是請求的目標是應用程序根目錄而且末尾沒有'/'符號結尾的話,那麼PATH_INFO可能爲空字符串 。
3. QUERY_STRING
URL請求中緊跟在「?」後面的那部分,它能夠爲空或不存在。
4. CONTENT_TYPE
HTTP請求中Content-Type字段包含的全部內容,它能夠爲空或不存在。
5. HTTP_ 變量組
這組變量對應着客戶端提供的HTTP請求報頭(即那些名字以 「HTTP_」 開頭的變量)
...
複製代碼
咱們其實上面經過框架
pprint.pprint(environ)
複製代碼
能夠查看到裏面所包含的信息。curl
{
'Apple_PubSub_Socket_Render':'/private/tmp/com.apple.launchd.9BSE0tnnTO/Render',
'CLICOLOR': '1',
'COLORFGBG': '7;0',
'COLORTERM': 'truecolor',
'CONTENT_LENGTH': '',
'CONTENT_TYPE': 'text/plain',
'FLUTTER_STORAGE_BASE_URL': 'https://storage.flutter-io.cn',
'GATEWAY_INTERFACE': 'CGI/1.1',
'GOBIN': '/Users/xx/Documents/goBin',
'GOPATH': '/Users/xx/Documents/goWorkPlace',
'GOROOT': '/usr/local/go',
'HOME': '/Users/xx',
'HTTP_ACCEPT': '*/*',
'HTTP_HOST': '0.0.0.0:5000',
'HTTP_USER_AGENT': 'curl/7.54.0',
'ITERM_PROFILE': 'Default',
'ITERM_SESSION_ID': 'w0t0p0:D66287F5-65FC-4141-94AC-06A1B3CBEAE4',
'LANG': 'zh_CN.UTF-8',
'LOGNAME': 'xx',
'LSCOLORS': 'exfxhxhxgxhxhxgxgxbxbx',
'PATH': '/Users/xx/.local/share/virtualenvs/flask-demo-MqfCTpGB/bin:/Users/xx/Documents/flutter/bin:/Users/xx/.pyenv/plugins/pyenv-virtualenv/shims:/Users/xx/.pyenv/plugins/pyenv-virtualenv/shims:/Users/xx/.pyenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Users/xx/.local/bin:/usr/local/go/bin:/Users/xx/Documents/goBin',
'PATH_INFO': '/',
'PIPENV_ACTIVE': '1',
'PIP_DISABLE_PIP_VERSION_CHECK': '1',
'PIP_PYTHON_PATH': '/Users/xx/.pyenv/versions/3.6.0/bin/python3.6',
'PS1': '(flask-demo) \\[\\033[01;33m\\]\\u \\W\\$\\[\\033[00m\\] ',
'PUB_HOSTED_URL': 'https://pub.flutter-io.cn',
'PWD': '/Users/xx/Documents/GitHub/flask-demo',
'PYENV_SHELL': 'bash',
'PYENV_VIRTUALENV_INIT': '1',
'PYTHONDONTWRITEBYTECODE': '1',
'QUERY_STRING': '',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_HOST': '',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': '',
'SERVER_NAME': 'XxdeMacBook-Pro.local',
'SERVER_PORT': '5000',
'SERVER_PROTOCOL': 'HTTP/1.1',
'SERVER_SOFTWARE': 'WSGIServer/0.2',
'SHELL': '/bin/bash',
'SHLVL': '2',
'SSH_AUTH_SOCK': '/private/tmp/com.apple.launchd.qMWayGCpdP/Listeners',
'TERM': 'xterm-256color',
'TERM_PROGRAM': 'iTerm.app',
'TERM_PROGRAM_VERSION': '3.2.0',
'TERM_SESSION_ID': 'w0t0p0:D66287F5-65FC-4141-94AC-06A1B3CBEAE4',
'TMPDIR': '/var/folders/6g/kjvjmf8j59j2tf2mm360dqjm0000gn/T/',
'USER': 'xx',
'VIRTUAL_ENV': '/Users/xx/.local/share/virtualenvs/flask-demo-MqfCTpGB',
'XPC_FLAGS': '0x0',
'XPC_SERVICE_NAME': '0',
'_': '/Users/xx/.local/share/virtualenvs/flask-demo-MqfCTpGB/bin/python',
'__CF_USER_TEXT_ENCODING': '0x1F5:0x19:0x34',
'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>,
'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>,
'wsgi.input': <_io.BufferedReader name=6>,
'wsgi.multiprocess': False,
'wsgi.multithread': True,
'wsgi.run_once': False,
'wsgi.url_scheme': 'http',
'wsgi.version': (1, 0)
}
複製代碼
在application裏面咱們經過environ得到咱們須要的不少參數, 好比請求的查詢字符串等。函數
# request.py
from six.moves import urllib
class Request(object):
"""接受environ參數, 而後一些子函數供外界使用去獲取須要的值"""
def __init__(self, environ):
self.environ = environ
def args(self):
""" 把查詢參數轉成字典形式 """
get_arguments = urllib.parse.parse_qs(
self.environ['QUERY_STRING']
)
return {k: v[0] for k, v in get_arguments.items()}
def path(self):
return self.environ['PATH_INFO']
複製代碼
# response.py
import http.client
from six.moves import urllib
from wsgiref.headers import Headers
class Response(object):
"""返回內容, 狀態碼, 字符編碼, 返回類型等"""
def __init__(self, response=None, status=200,
charset='utf-8', content_type='text/html'):
self.response = [] if response is None else response
self.charset = charset
self.headers = Headers()
content_type = '{content_type}; charset={charset}'.format(
content_type=content_type, charset=charset)
self.headers.add_header('content-type', content_type)
self._status = status
@property
def status(self):
status_string = http.client.responses.get(self._status, 'UNKNOWN')
return '{status} {status_string}'.format(
status=self._status, status_string=status_string)
def __iter__(self):
for val in self.response:
if isinstance(val, bytes):
yield val
else:
yield val.encode(self.charset)
複製代碼
# transfer.py
from request import Request
def request_response_application(func):
"""把WSGI 函數轉換成使用Request/Response 對象"""
def application(environ, start_response):
request = Request(environ)
response = func(request)
start_response(
response.status,
response.headers.items()
)
return iter(response)
return application
複製代碼
# wsgi_demo.py
import pprint
# 導入python內置的wsgi server
from wsgiref.simple_server import make_server
from transfer import request_response_application
from response import Response
@request_response_application
def application(request):
# 獲取查詢字符串中的 name
name = request.args().get('name', 'default_name')
return Response(['<h1>hello {name}</h1>'.format(name=name)])
if __name__ == '__main__':
httpd = make_server('0.0.0.0', 5000, application)
httpd.serve_forever()
複製代碼
python wsgi_demo.py
複製代碼
默認狀況:
~$ curl http://0.0.0.0:5000/
<h1>hello default_name</h1>
複製代碼
帶有name的查詢字符串
~$ curl http://0.0.0.0:5000/demo?name=kobe
<h1>hello kobe</h1>
複製代碼