了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:

  1. 浏览器发送一个HTTP请求;

  2. 服务器收到请求,生成一个HTML文档;

  3. 服务器把HTML文档作为HTTP响应的Body发送给浏览器;

  4. 浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。

所以,最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。Apache、Nginx、Lighttpd等这些常见的静态服务器就是干这件事情的。

如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。

这个接口就是WSGI:Web Server Gateway Interface。

WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。我们来看一个最简单的Web版本的“Hello, web!”:

def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return '<h1>Hello, web!</h1>'

上面的application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:

  • environ:一个包含所有HTTP请求信息的dict对象;

  • start_response:一个发送HTTP响应的函数。

application()函数中,调用:

start_response('200 OK', [('Content-Type', 'text/html')])

就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每个Header用一个包含两个strtuple表示。

通常情况下,都应该把Content-Type头发送给浏览器。其他很多常用的HTTP Header也应该发送。

然后,函数的返回值'<h1>Hello, web!</h1>'将作为HTTP响应的Body发送给浏览器。

有了WSGI,我们关心的就是如何从environ这个dict对象拿到HTTP请求信息,然后构造HTML,通过start_response()发送Header,最后返回Body。

整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,我们只负责在更高层次上考虑如何响应请求就可以了。

不过,等等,这个application()函数怎么调用?如果我们自己调用,两个参数environstart_response我们没法提供,返回的str也没法发给浏览器。

所以application()函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。但是现在,我们只想尽快测试一下我们编写的application()函数真的可以把HTML输出到浏览器,所以,要赶紧找一个最简单的WSGI服务器,把我们的Web应用程序跑起来。

好消息是Python内置了一个WSGI服务器,这个模块叫wsgiref,它是用纯Python编写的WSGI服务器的参考实现。所谓“参考实现”是指该实现完全符合WSGI标准,但是不考虑任何运行效率,仅供开发和测试使用。

运行WSGI服务

我们先编写hello.py,实现Web应用程序的WSGI处理函数:

# hello.py

def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return '<h1>Hello, web!</h1>'

然后,再编写一个server.py,负责启动WSGI服务器,加载application()函数:

# server.py
# 从wsgiref模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的application函数:
from hello import application # 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
print "Serving HTTP on port 8000..."
# 开始监听HTTP请求:
httpd.serve_forever()

确保以上两个文件在同一个目录下,然后在命令行输入python server.py来启动WSGI服务器:

注意:如果8000端口已被其他程序占用,启动将失败,请修改成其他端口。

启动成功后,打开浏览器,输入http://localhost:8080/,就可以看到结果了:

# wsgi app

def application(environ, start_response):
response_body = "<h1>Hello World</h1>"
header = [('Content-Type', 'text/html')]
status = "200 OK"
start_response(status, header)
print "environ http request method:"+environ['REQUEST_METHOD']
return [response_body] if __name__ == "__main__":
from wsgiref.simple_server import make_server
httpd = make_server("0.0.0.0", 8080, application)
print "httpd run on :"+str(httpd.server_port)
httpd.serve_forever()

wsgi app

小结

无论多么复杂的Web应用程序,入口都是一个WSGI处理函数。HTTP请求的所有输入信息都可以通过environ获得,HTTP响应的输出都可以通过start_response()加上函数返回值作为Body。

复杂的Web应用程序,光靠一个WSGI函数来处理还是太底层了,我们需要在WSGI之上再抽象出Web框架,进一步简化Web开发。

为什么需要有 WSGI 协议,用 WSGI 协议的地方为何不直接用http?为什么要翻译一次?

问1:一个 HTTP 请求到达对应的 application处理函数要经过怎样的过程?

问2:如何不通过流行的 web 框架来写一个简单的web服务?

一个HTTP请求的过程可以分为两个阶段,第一阶段是从客户端到WSGI Server,第二阶段是从WSGI Server 到WSGI Application

今天主要是讲第二阶段,主要内容有以下几点:

  1. WSGI 是什么,因何而生?
  2. 为什么需要有 WSGI?(补充)
  3. HTTP请求是如何到应用程序的?

01. WSGI 是什么,因何而生?

WSGI是 Web Server Gateway Interface 的缩写。

它是 Python应用程序(application)或框架(如 Django)和 Web服务器之间的一种接口,已经被广泛接受。

它是一种协议,一种规范,其是在 PEP 333提出的,并在 PEP 3333 进行补充(主要是为了支持 Python3.x)。这个协议旨在解决众多 web 框架和web server软件的兼容问题。有了WSGI,你不用再因为你使用的web 框架而去选择特定的 web server软件。

常见的web应用框架有:Django,Flask等

常用的web服务器软件有:uWSGI,Gunicorn等

那这个 WSGI 协议内容是什么呢?知乎上有人将 PEP 3333 翻译成中文,写得非常好,我将这段协议的内容搬运过来。

WSGI 接口有服务端和应用端两部分,服务端也可以叫网关端,应用端也叫框架端。服务端调用一个由应用端提供的可调用对象。如何提供这个对象,由服务端决定。例如某些服务器或者网关需要应用的部署者写一段脚本,以创建服务器或者网关的实例,并且为这个实例提供一个应用实例。另一些服务器或者网关则可能使用配置文件或其他方法以指定应用实例应该从哪里导入或获取。

WSGI 对于 application 对象有如下三点要求

  1. 必须是一个可调用的对象
  2. 接收两个必选参数environ、start_response。
  3. 返回值必须是可迭代对象,用来表示http body。

02. 为什么要有WSGI?

这是来自评论区的一个问题,我觉得问得很好,所以来答一下,更新在这里。

请教下用wsgi协议的地方为何不直接用http?为什么要翻译一次?

以下是我的回答,个人理解,仅供交流。

web框架(即app)在生产中一般不用于直接接收http请求。

你可能会说,django不就可以直接接收http请求吗,也不需要uwsgi之类的所谓的服务器。

其实不是,django只是在其内部自己实现了一个简易的web服务器,以供开发调试之用。所以初学者往往会误以为,web app框架本身就可以接收http请求。

web 服务器 和 web 框架,分工不同,职责不同(web 服务器专注于接收并解析请求以调用的方式将请求的内容传web框架),缺一不可,可以说它们是两个组件,共同协作才能实现web网页的访问,既然是两个组件,那总要定义一些约定俗成的通讯协议,而这就是WSGI,所以必须有WSGI。

那接下来,就引出另一个问题了:如果它们不分开,而将二者整合在一起,对外只有一个组件,是不是就没有WSGI什么事了?

答案,是的。

但是你也可以发现目前市场上有相当多的大大小小的web开发框架,如果每个框架都去自己实现web服务器,那岂不是重复造轮子?

最好的情况应该是,由专业的团队去开发专业的web服务器,而开发出来的web服务器需要具备框架通用性,Django可以用,Flask也可以用,开发者也可以自由选择用哪个web 服务器软件,用哪个web 框架,灵活组合。

03. HTTP请求是如何到应用程序的?

当客户端发出一个 HTTP 请求后,是如何转到我们的应用程序处理并返回的呢?

关于这个过程,细节的点这里没法细讲,只能讲个大概。

我根据其架构组成的不同将这个过程的实现分为两种:

1、两级结构 在这种结构里,uWSGI作为服务器,它用到了HTTP协议以及wsgi协议,flask应用作为application,实现了wsgi协议。当有客户端发来请求,uWSGI接受请求,调用flask app得到相应,之后相应给客户端。 这里说一点,通常来说,Flask等web框架会自己附带一个wsgi服务器(这就是flask应用可以直接启动的原因),但是这只是在开发阶段用到的,在生产环境是不够用的,所以用到了uwsgi这个性能高的wsgi服务器。

2、三级结构 这种结构里,uWSGI作为中间件,它用到了uwsgi协议(与nginx通信),wsgi协议(调用Flask app)。当有客户端发来请求,nginx先做处理(静态资源是nginx的强项),无法处理的请求(uWSGI),最后的相应也是nginx回复给客户端的。 多了一层反向代理有什么好处?

提高web server性能(uWSGI处理静态资源不如nginx;nginx会在收到一个完整的http请求后再转发给wWSGI)

nginx可以做负载均衡(前提是有多个服务器),保护了实际的web服务器(客户端是和nginx交互而不是uWSGI)

https://zhuanlan.zhihu.com/p/68676316

https://www.liaoxuefeng.com/wiki/897692888725344/923057027806560

Red Hat快捷键操作的更多相关文章

  1. Red Hat、Fedora和Ubuntu软件包操作

    五.Red Hat.Fedora和Ubuntu软件包操作对比 最后总结: 在 /etc/yum.conf 的 [main] 后面添加以下配置即可! 复制代码 代码如下: exclude=kernel* ...

  2. 使用 KGDB 调试 Kernel On Red Hat Linux

    1. KGDB 简介         KGDB  提供了一种使用 GDB 调试 Linux 内核的机制.使用 KGDB 可以象调试普通的应用程序那样,在内核中进行设置断点.检查变量值.单步跟踪程序运行 ...

  3. Linux:Red Hat系统的安装

    今天高兴,所以我写这一期,这一期写的是Red Hat系统的安装,这个开发系统也是红帽企业制作出来的,关于这款系统的相关资料就自行百度吧!话不多说,直接进入这期的内容吧! 安装Red Hat系统 系统下 ...

  4. VS Code拓展--Language Support for Java(TM) by Red Hat(1.3.0)

    Language Support for Java(TM) by Red Hat(1.3.0) 注意:版本问题,可能会有部分出入 功能目录 设置 java.home 作用: 指定用于启动 Java 语 ...

  5. Red hat 6.4下面的qt安装

    运行环境:Red hat 6.4 去官网下载qt5.2并且安装 当启动的时候会出现如下错误 核心载入失败: /opt/Qt5.2.0/Tools/QtCreator/lib/qtcreator/plu ...

  6. Red Hat Enterprise Server 5.8+oracle10g(中文界面)安装

    Red Hat Enterprise Server 5.8+oracle10g(中文界面)安装 VMware workstation10(虚拟机)下面安装红帽企业版5.8 创建虚拟机 新建虚拟机,选择 ...

  7. VMware 虚拟机Red Hat 5.9 交换区及硬盘空间调整

    首先要通过VMware设置简单实现内存扩大.但是系统中的/swap应该如何设置呢? 1. 创建swap 文件 使用如下命令: #dd if=/dev/zero of=/swap/swapfile bs ...

  8. Red Hat Linux认证

    想系统的学习一下Linux,了解了一些关于Red Hat Linux认证的信息.整理如下. 当前比较常见的是RHCE认证,即Red Hat Certified Engineer.最高级别的是RHCA ...

  9. Red Hat Enterprise Linux 5安装序列号

    为了保证安装的组件和订阅相匹配,红帽企业 Linux 5 需要输入一个安装号.它被用来配置安装程序来提供正确的软件包.安装号码包含在你的订阅里. 如果您没有输入安装号码,只有核心服务器或 Deskto ...

随机推荐

  1. Android的各版本间的区别总结

    Android 1.0 第一版商用操作系统 Android 1.1 更新了部分API,新增一些功能,修正了一些错误,同时增加com.google.android.maps包 Android 1.5智能 ...

  2. Linux命令-工作管理命令:&,ctrl+z,jobs,fg,bg

    在linux下面将一个进程放入后台执行,有两种方式: 第一种方式:&表示命令在后台执行程序,等同于windows里面的程序最小化. 第二种方式:执行某一个命令,例如:top,然后按ctrl+z ...

  3. 转 jmeter使用IP欺骗压力测试

    jmeterIP 欺骗多IP 最近在使用jmeter进行压力测试时需要使用类似于loadrunner的IP欺骗功能,经问津度娘无果后决定再次耐心研究jmeter官方文 档,终于发现在jmeter2.5 ...

  4. Android多点触摸放大缩小图片

    1.Activity package com.fit.touchimage; import android.app.Activity; import android.graphics.Bitmap; ...

  5. POSIX 消息队列 和 系列函数

    一.在前面介绍了system v 消息队列的相关知识,现在来稍微看看posix 消息队列. posix消息队列的一个可能实现如下图: 其实消息队列就是一个可以让进程间交换数据的场所,而两个标准的消息队 ...

  6. 怎么修改Elasticsearch的对外ip 默认是本地IP 127.0.0.1

    //修改C:\Program Files\elasticsearch-2.1.1\config\elasticsearch.yml: network.bind_host: 172.16.1.86 pa ...

  7. 怎么把本地的文件放到esxi主机上

    我们登录到esxi主机后 然后我们点击摘要-->存储器--->右键,浏览数据存储 创建文件夹,然后选择上传到此文件存储

  8. 给 Android 开发人员的 RxJava 具体解释

    鉴于 RxJava 眼下这样的既火爆又神奇的现状,而我又在一年的使用过程中对 RxJava 有了一些理解,我决定写下这篇文章来对 RxJava 做一个相对具体的.针对 Android 开发人员的介绍. ...

  9. 算法练习:最小生成树 (Minimum Spanning Tree)

    (注:此贴是为了回答同事提出的一个问题而匆匆写就,算法代码只求得出答案为目的,效率方面还有很大的改进空间) 最小生成树是指对于给定的带权无向图,需要生成一个总权重最小的连通图.其问题描述及算法可以详见 ...

  10. [na]交换技术知识点-提纲

    vlan - trunk - vtp(vtp prune) stp portfast rootgurd bpduguard bpdufilter uplinkfast backbonfast loop ...