原文https://yukunweb/2018/2/understand-python-web/
因为 python代码的优雅美观且易于维护这一特点越来越多的人选择使用Python做Web开发。而Python的Web框架百花齐放目前比较流行的框架有大包大揽的Django小巧灵活的Flask、Bottle还有性能高效的异步框架Tornado、sanic。这么多框架只要选择一个阅读他的文档就可以很轻松的搭建一个web app完全不需要去管他实现的原理。
本篇文章意在对一个web开发做一个梳理。
前端网页三剑客
我们打开浏览器输入一个网址 yukunweb然后就看到了浏览器给我们显示的页面这个时候打开浏览器开发者工具点击Network刷新页面会看到下方的请求的url点击Response就可以看到服务器返回给浏览器的html文件信息了。如果复制Response响应的内容保存为index.html并且在浏览器打开依然可以看到首页的内容但是似乎缺少了一些页面的样式和功能。
这是因为当浏览器接收到首页的 HTML源码后它会根据HTML的规则去显示页面然后再根据HTML里的链接自动发送HTTP请求给服务器拿到相应的图片和Javascript、CSS等资源最终显示出一个完整的页面。所以我们会在Network下面能看到很多额外的以.js.css等后缀的请求了。
其实我们看到的页面就是浏览器按照 HTML的规则展示给我们的。HTML告诉浏览器那里是导航那里是主栏那里是侧栏。而这些信息如何显示或者是显示的样式就是CSS文件的功劳。至于比如导航的下拉隐藏上拉显示就是Javascript的作用。
如果想要做Web开发就一定得熟悉 HTML、CSS、Javascript三剑客的知识这里推荐W3school的前端教程也是我学习前端的地方W3school
客户端和服务器通信
理解了前段三剑客就知道如何去写一个网页。那么从我们在浏览器的地址栏输入 URL到Web页面呈现出来到底经历了什么。
如图一般这种通过发送请求获取服务器资源的Web浏览器都可以称为客户端(client)。首先发送一个请求(request)给服务器大多是以GET请求方式访问服务器接收到你的请求然后取到请求的资源返回给客户端。
服务器和客户端之间交流是怎么进行的呢服务器是怎么理解客户端的请求的呢。这里就需要一种协议规范就是HTTP(HyperText Transfer Protocol超文本传输协议)。可以说 Web是建立在HTTP协议上通信的。
如图仍然是之前的例子打开浏览器访问 yukunweb打开浏览器开发者工具点击图中标记的选项卡(记得点view parsed)可以看到客户端发给服务器的请求头前两行。
GET / HTTP/1.1
Host: yukunweb
第一行开头的GET表示请求访问服务器的类型称为方法(method)。随后的字符 /指明了请求访问的资源对象即请求URI。最后的HTTP/1.1即HTTP的版本号用来提示客户端使用的HTTP协议功能。
综上所述第一行请求内容的意思是请求访问某台 HTTP服务器上的/(首页)页面资源。所以第二行的Host表示请求的域名也就是服务器所在地址。
如图如果是 POST请求的话不仅会有请求头部信息还有一个Form Data的请求实体内容。
接收到请求的服务器呢他会将请求内容的处理结果以响应的形式返回看图中的第一行
开头的部分仍然是服务器对应的 HTTP版本紧接着的200 OK表示请求的处理结果的状态码 (status code) 和原因短语。200状态码就表示响应成功常见的404表示访问错误500表示服务器响应错误。这里的OK是没有固定的规则的你也可以让他返回GOOD啥的。
下一行是服务器信息本站用的是 Nginx服务器在下一行显示了创建响应的日期时间。在下一行的Content-Type表示内容的类型客户端会依赖他判断响应的内容是网页还是音频图片等类型。
这里只是简单的介绍了 HTTP协议即是客户端与服务器之间的通信协议。如果想要深入了解推荐阅读《HTTP权威指南》。
WSGI
如果你浏览一个地址 http://yukunweb/search-result/?keywords音乐你会访问到本站的音乐关键词的搜索结果。我们知道客户端发送请求给服务器那么服务器是怎么拿到资源的呢。其实这是交给后端运行的应用返回的好比你抓取一个页面到获取到信息这些逻辑的处理肯定是我们的程序再跑。
但是接收并且解析客户端的 HTTP请求在发送HTTP响应这些底层操作后端的程序肯定是不会去处理的。所以要想只专注于Web业务逻辑还需要一个服务器和web应用之间的嫁接层————WSGI。
什么是WSGI(Web Server Gateway Interface)
WSGI翻译过来就是Web服务器网关接口。他只是一个规范定义了Web服务器如何与Python应用程序进行交互使得使用Python写的Web应用程序可以和Web服务器(nginx/apache)对接起来。
该规范的地址PEP 333
WSGI是Python的Web开发的基石有了它你就有了一切它存在的目的有两个
描述 Web 服务器如何与 Web 应用程序交互将客户端请求传给应用程序
描述 Web 应用程序如何处理请求和如何返回数据给服务器。
由于 Python内置的标准库里有一个WSGI库wsgiref我们基于他来写一个体现WSGI目的的例子
from wsgiref.simple_server import make_server
def application(environ, start_response):
status 200 OK
response_headers [(Content-type, text/html)]
start_response(status, response_headers)
body Hello, {name} !!!.format(nameenviron[PATH_INFO][1:] or WSGI)
return [body.encode(utf-8)]
app make_server(, 8000, application)
app.serve_forever
运行程序如果没有报错此时打开浏览器输入地址 127.0.0.1:8000和127.0.0.1:8000/GuTianle就可以看到程序返回的页面了。如图
我们可以看到一个请求他的入口只需要一个 WSGI的处理函数。因为所有的请求信息都包含在environ中这样我们就可以根据这些信息去返回不同的数据。
参数
environ字典类型存放了所有和客户端相关的信息。如果想知道他里面有哪些参数可以更改上面的代码在 return 行上面加一个 for k, v in environ.items的循环打印出字典里的所有参数。
startresponse一个可调用对象接收两个必选参数和一个可选参数:
status: 一个字符串表示 HTTP 响应状态字符串如 200404
responseheaders: 一个列表包含有如下形式的元组(headername, headervalue)用来表示 HTTP 响应的 headers 如(Content-type, text/html)
exc_info可选: 用于出错时服务器需要返回给浏览器的信息
返回一个可迭代对象, 服务器通过遍历这个可迭代对象可以获得body的全部内容内容可以是 html也可以是json。
这里简单的介绍了 WSGI是什么干什么。如果理解了WSGI那么写一个Python的Web框架就很简单了。这也是为什么Python有成百上千web框架的原因。
实现基于WSGI的框架
上面我们理解了 WSGI是干什么的那么我们基于它实现一个简单的web框架可以说轻而易举了。
from wsgiref.simple_server import make_server
class Application(object):
def __init__(self, environ, start_response):
self.start_response start_response
self.path environ[PATH_INFO]
def __iter__(self):
if self.path /:
status 200 OK
response_headers [(Content-type, text/html)]
self.start_response(status, esponse_headers)
yield Hello,World!.encode(utf-8)
elif self.path /wsgi:
status 200 OK
response_headers [(Content-type, text/html)]
self.start_response(status, response_headers)
yield Hello,WSGI!.encode(utf-8)
else:
status 404 NOT FOUND
response_headers [(Content-type, text/html)]
self.start_response(status, response_headers)
yield 404 NOT FOUND.encode(utf-8)
if __name__ "__main__":
app make_server(127.0.0.1, 8000, Application)
print(Serving HTTP on port 8000...)
app.serve_forever
这个 Application类只不过是对WSGI又做了一层简单的封装而已由于上面说过WSGI函数返回的是一个可以迭代对象所以需要实现一个iter方法里面控制了客户端的请求路由并且返回不同的输出。
当然如果你想扩展成一个像样的框架还需要考虑很多比如像 flask那样方便的路由系统还有对于用户请求方式的处理等等。总之是个很需要折腾的过程好比flask的0.1版本去掉注释也就 200 多行而如今最新版本。。。
题图pexelsCC0 授权。
【转自:美国cn2服务器 http://www.558idc.com/mg.html欢迎留下您的宝贵建议】