php的wsgi框架结构,理解 WSGI 框架
This document specifies a proposed standard interface between web servers and Python web applications or frameworks, to promote web application portability across a variety of web servers.
-—–PEP 0333
An Introduction to WSGI
在 java web 領(lǐng)域,支持?servlet API?的 java application 都可運(yùn)行在支持 servlet API 的 web server (http server) 上。隨著 web 不斷發(fā)展,python application/framework 也如雨后春筍般涌出,如:zope, webware, skunkweb 等等。但是它們的接口存在差異,導(dǎo)致難以跨 web server 運(yùn)行,所以 python 社區(qū)定義了一種如 servlet API 般標(biāo)準(zhǔn)通用的接口——WSGI。
PEP 0333 – Python Web Server Gateway Interface?是一種?web server or gateway?和 python?web application or framework?之間簡(jiǎn)單通用的接口,符合這種接口的 application 可運(yùn)行在所有符合該接口的 server 上。通俗的講,WSGI 規(guī)范了一種簡(jiǎn)單的接口,解耦了 server 和 application,使得雙邊的開(kāi)發(fā)者更加專(zhuān)注自身特性的開(kāi)發(fā)。
Web server/gateway: 即 HTTP Server,處理 HTTP 協(xié)議,接受用戶(hù) HTTP 請(qǐng)求和提供并發(fā),調(diào)用 web application 處理業(yè)務(wù)邏輯。通常采用 C/C++ 編寫(xiě),代表:apache, nginx 和 IIS。
Python Web application/framework: 專(zhuān)注業(yè)務(wù)邏輯的 python 應(yīng)用或者框架。
The Application/Framework Side
Application/framework 端必須定義一個(gè) callable object,callable object 可以是以下三者之一:
function, method
class
instance with a __call__ method
Callable object 必須滿(mǎn)足以下兩個(gè)條件:
接受兩個(gè)參數(shù):字典(environ),回調(diào)函數(shù)(start_response,返回 HTTP status,headers 給 web server)
返回一個(gè)可迭代的值
基于 callable function 的 application/framework 樣例如下:
Python
1
2
3
def
application
(
environ
,
start_response
)
:
start_response
(
'200 OK'
,
[
(
'Content-Type'
,
'text/plain'
)
]
)
return
[
'This is a python application!'
]
基于 callable class 的 application/framework 樣例如下:
Python
1
2
3
4
5
6
7
8
class
ApplicationClass
(
object
)
:
def
__init__
(
self
,
environ
,
start_response
)
:
self
.
environ
=
environ
self
.
start_response
=
start_response
def
__iter__
(
self
)
:
self
.
start_response
(
'200 OK'
,
[
(
'Content-type'
,
'text/plain'
)
]
)
yield
"Hello world!n"
The Server/Gateway Side
Server/gateway 端主要專(zhuān)注 HTTP 層面的業(yè)務(wù),重點(diǎn)是接收 HTTP 請(qǐng)求和提供并發(fā)。每當(dāng)收到 HTTP 請(qǐng)求,server/gateway 必須調(diào)用 callable object:
接收 HTTP 請(qǐng)求,但是不關(guān)心 HTTP url, HTTP method 等
為?environ?提供必要的參數(shù),實(shí)現(xiàn)一個(gè)回調(diào)函數(shù)?start_response,并傳給 callable object
調(diào)用 callable object
我們直接使用支持 WSGI 框架的?wsgiref?庫(kù),編寫(xiě)一個(gè)樣例:
1
2
3
4
5
6
7
8
9
10
# application/framework side
def
application
(
environ
,
start_response
)
:
start_response
(
'200 OK'
,
[
(
'Content-Type'
,
'text/plain'
)
]
)
return
[
'This is a python application!'
]
# server/gateway side
if
__name__
==
'__main__'
:
from
wsgiref
.
simple_server
import
make_server
server
=
make_server
(
'0.0.0.0'
,
8080
,
application
)
server
.
serve_forever
(
)
運(yùn)行后,對(duì)于任意的 url 和 method,本例的返回值均為 ‘This is a python application!’:
1
2
3
4
5
$
curl
127.0.0.1
:
8080
This
is
a
python
application
!
$
curl
127.0.0.1
:
8080
/
test
This
is
a
python
application
!
Middleware: Components that Play Both Sides
Unix philosophy: do one thing and do it well.
Middleware 處于 server/gateway 和 application/framework 之間,對(duì) server/gateway 來(lái)說(shuō),它相當(dāng)于 application/framework;對(duì) application/framework 來(lái)說(shuō),它相當(dāng)于 server/gateway。每個(gè) middleware 實(shí)現(xiàn)不同的功能,我們通常根據(jù)需求選擇相應(yīng)的 middleware 并組合起來(lái),實(shí)現(xiàn)所需的功能。比如,可在 middleware 中實(shí)現(xiàn)以下功能:
根據(jù) url 把用戶(hù)請(qǐng)求調(diào)度到不同的 application 中。
負(fù)載均衡,轉(zhuǎn)發(fā)用戶(hù)請(qǐng)求
預(yù)處理 XSL 等相關(guān)數(shù)據(jù)
限制請(qǐng)求速率,設(shè)置白名單
WSGI 的 middleware 體現(xiàn)了 unix 的哲學(xué)之一:do one thing and do it well。事實(shí)上,在定義 WSGI 框架的時(shí)候,設(shè)計(jì)者就要求 server/gateway 和 application/framework 雙方盡可能的簡(jiǎn)單,同時(shí)也要求 middleware 設(shè)計(jì)的簡(jiǎn)單而專(zhuān)一,PEP 333 提到:
If middleware can be both simple and robust, and WSGI is widely available in servers and frameworks, it allows for the possibility of an entirely new kind of Python web application framework: one consisting of loosely-coupled WSGI middleware components.
本例實(shí)現(xiàn)了一個(gè) IPBlacklist 的 middleware:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class
IPBlacklistMiddleware
(
object
)
:
def
__init__
(
self
,
app
)
:
self
.
app
=
app
def
__call__
(
self
,
environ
,
start_response
)
:
ip_addr
=
environ
.
get
(
'HTTP_HOST'
)
.
split
(
':'
)
[
0
]
if
ip_addr
not
in
(
'127.0.0.1'
)
:
return
forbidden
(
start_response
)
return
self
.
app
(
environ
,
start_response
)
def
forbidden
(
start_response
)
:
start_response
(
'403 Forbidden'
,
[
(
'Content-Type'
,
'text/plain'
)
]
)
return
[
'Forbidden'
]
def
application
(
environ
,
start_response
)
:
start_response
(
'200 OK'
,
[
(
'Content-Type'
,
'text/plain'
)
]
)
return
[
'This is a python application!'
]
if
__name__
==
'__main__'
:
from
wsgiref
.
simple_server
import
make_server
application
=
IPBlacklistMiddleware
(
application
)
server
=
make_server
(
'0.0.0.0'
,
8080
,
application
)
server
.
serve_forever
(
)
測(cè)試如下:
1
2
3
4
5
6
7
# 從本機(jī)測(cè)試
$
curl
127.0.0.1
:
8080
/
test
This
is
a
python
application
!
# 從其它主機(jī)測(cè)測(cè)試
$
curl
10.10.10.2
:
8080
/
test
Forbidden
Path Dispatching
至此樣例的一個(gè)不足之處是對(duì)于任意的 url 和 method,程序的返回值均為 ‘This is a python application!’,所以我們需要增加 path dispatch 功能。由于 WSGI 框架下的 server/gateway 不處理 url 和 method,所以 url mapping 需由 application/framework 端完成。注意到參數(shù)?environ,它包含以下變量:
REQUEST_METHOD: 即 HTTP method
PATH_INFO: 即 HTTP url
所以 application/framework 可以根據(jù) environ 的 REQUEST_METHOD 和 PATH_INFO 實(shí)現(xiàn) path dispatch,樣例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class
IPBlacklistMiddleware
(
object
)
:
def
__init__
(
self
,
app
)
:
self
.
app
=
app
def
__call__
(
self
,
environ
,
start_response
)
:
ip_addr
=
environ
.
get
(
'HTTP_HOST'
)
.
split
(
':'
)
[
0
]
if
ip_addr
not
in
(
'127.0.0.1'
)
:
return
forbidden
(
start_response
)
return
self
.
app
(
environ
,
start_response
)
def
dog
(
start_response
)
:
start_response
(
'200 OK'
,
[
(
'Content-Type'
,
'text/plain'
)
]
)
return
[
'This is dog!'
]
def
cat
(
start_response
)
:
start_response
(
'200 OK'
,
[
(
'Content-Type'
,
'text/plain'
)
]
)
return
[
'This is cat!'
]
def
not_found
(
start_response
)
:
start_response
(
'404 NOT FOUND'
,
[
(
'Content-Type'
,
'text/plain'
)
]
)
return
[
'Not Found'
]
def
forbidden
(
start_response
)
:
start_response
(
'403 Forbidden'
,
[
(
'Content-Type'
,
'text/plain'
)
]
)
return
[
'Forbidden'
]
def
application
(
environ
,
start_response
)
:
path
=
environ
.
get
(
'PATH_INFO'
,
''
)
.
lstrip
(
'/'
)
mapping
=
{
'dog'
:
dog
,
'cat'
:
cat
}
call_back
=
mapping
[
path
]
if
path
in
mapping
else
not_found
return
call_back
(
start_response
)
if
__name__
==
'__main__'
:
from
wsgiref
.
simple_server
import
make_server
application
=
IPBlacklistMiddleware
(
application
)
server
=
make_server
(
'0.0.0.0'
,
8080
,
application
)
server
.
serve_forever
(
)
測(cè)試如下:
1
2
3
4
5
6
7
8
$
curl
127.0.0.1
:
8080
/
dog
This
is
dog
!
$
curl
127.0.0.1
:
8080
/
cat
This
is
cat
!
$
curl
127.0.0.1
:
8080
/
monkey
Not
Found
總結(jié)
以上是生活随笔為你收集整理的php的wsgi框架结构,理解 WSGI 框架的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: oracle record 类型,Ora
- 下一篇: oracle中app文件夹下,Oracl