一、web程序的构成
一个web程序=web服务+web应用
- web服务:
核心职责:负责处理网络请求,解析http协议(浏览器与web服务之间默认用http协议通信) - web应用:
核心职责:负责业务逻辑处理、提供具体的网页内容
分成两部分的好处非常大:分工协作,各司其职,不同的程序员负责不同的事情,更专业,更高效
任何遇到web程序的地方,你都需要将其分成web服务与web应用这两个部分去看,我们接下来介绍的知识点,也是如此
二、最开始的web程序(纯静态)
最开的web程序只提供静态内容,它就像是把某份报纸放到了网上,所有用户只能看不能动/互动,并且所有用户看到内容都一模一样,
此时web程序的两大组成部分的开发是这样的
1、web应用:开发起来非常简单,web应用的构成就是一堆由html、css、图片等构成的静态文件,不需要有任何的逻辑处理,它就像是为访问者提供了一份报纸
2、web服务:开发起来也比较简单,就是解析http协议、匹配访问路径、找到本地的(web应用提供的)静态文件,然后返回给访问者
三、动态请求的诞生
举个例子:
1、蛮荒时代
你们家在中关村开实体店卖电脑,为了让电脑能够卖出去,你需要让更多的人知道你们家的电脑产品,于是,你不得不骑着破三轮大街小巷地吆喝:“我们的A款电脑会喷火、B款电脑会上树、C款电脑会飞。。。”,你一边喊着,一遍顺手在沿途的电线杆子上都贴上了你们家的小广告
2、静态网页时代:小广告搬到了线上
后来,你听人提起了互联网这个新颖的东西,据说现在越来越多的人喜欢通过网线跑到一台机器上看到这台机器上的文件,你灵机一动,文件里写上小广告的内容、配上图片配上宣传语,然后我就不用走街串巷吆喝&贴小广告了。用户通过一根网线就能看到,多么高效!
很快你的网站就上线了,很多人都可以上网观看你们家的电脑产品介绍,用户心想:这可比去电箱杆子上看小广告强多了。
就这样,网上看完广告的用户,很多都跑到线下你们实体店里付钱购买电脑,很快你就赚到了人生的第一桶金
3、动态网页时代:实体店也不用来了,直接网上付款吧
随着互联网的发展,用户不再满足于看静态内容,用户想要能够与网页互动,这边是动态内容的由来。啥是动态内容?
承接上面的例子:
用户开始抱怨,你们家电脑在网上的产品介绍确实很诱人,但是你们家的实体店真的太远了,我要坐11路转28路汽车坐5个小时的车才能到你们店里,太麻烦了!能不能直接网上付款????????
这便对你的网站提出新的需求,要求能够处理用户的付款逻辑
1、用户身份认证
2、用户余额查询
3、付款,余额减少
4、商品个数减少
以上逻辑处理,之前的静态网站是做不了的(因为它就像是一张报纸嘛),如何解决呢?
1、首先可以明确的一点就是,你必须针对用户的某一种动态请求开发相应的处理逻辑/业务逻辑,用perl、python等语言都可以
2、用户的动态需求可能会有付款、也可能会有退款等等各种各样的业务逻辑,即你需要开发多套程序来应对不同的业务逻辑,早期的时候处理一个业务逻辑就对应一个脚本程序,而且大多数都是perl写的
此时,web程序的开发是这样的
- 1、web服务:web服务的核心责任是处理http协议,所以为了分工明确,你不可能在web服务里加入处理业务逻辑的代码,如果你真想那么做,那就是直接退回到web服务与web应用不分家的时代,你自己全搞得了。很明显不合理。想要不违背web服务的核心职责、还能满足动态请求的需求,只需要为web服务增加一个可以调用其他程序的功能就可以,事实上web服务就是这么干的:一旦发现是动态请求,则触发一个脚本的执行(这个脚本用perl、用shell、用python写都可以)
2、脚本里需要:能识别web服务传来的http协议,执行上面的业务逻辑
除了用户付款外,可能还有很多其他业务逻辑,每一个逻辑都写一个脚本就行,如此,web服务便可以针对不同的动态请求转发给不同的脚步处理
3、脚本处理完毕之后,web服务拿到响应的结果返回用户就可以了
总结:此时的web程序
1、web应用:静态文件+一堆用于处理各种业务的逻辑的脚本(主要是per语言写的)
2、web服务:解析http协议、匹配访问路径,静态请求直接返回对应的静态文件,动态请求则调用响应的脚本拿到结果后返回、找到本地的然后返回给访问者
四、cgi协议的诞生
从动态网站诞生之初,web服务与web应用之间交互,用的直接就是http协议,这意味着web应用程序里也需要能够解析http协议,
本来这部分工作都是全权交给web服务来处理的,导致现在web应用程序员被逼着要学习http协议—>在自己的脚本里要处理http协议
非常的麻烦
web应用程序员开始骂娘了:"你们负责开发web服务的程序员真是屁用没有,本来指望着你们能把复杂的http协议给处理了,就不用让我们web应用再费劲了,现在看,还得我们web应用来处理http协议,那还要你们web服务干啥,我们全都干了,你们全下岗得了"
web服务的开发者听了之后觉得有道理,很羞愧,于是大家就开始一起想办法,力求能够屏蔽到复杂的http协议,让后面的web应用能够非常简单的处理http协议
怎么办呢?cgi(Common Gateway Interface)通用网关接口协议应运而生,cgi最先就是用在web服务与web应用之间,本质就是对http协议封装之后的一个上层协议,web服务在解析完用户发来的http协议请求后,会将http相关的关键信息都按照cgi协议组织好,如果说http协议是一堆汽车零件,那cgi协议就相当于帮你组装好了一台汽车,你用不着去学习发动机是咋构造的、冒烟筒子是如何冒烟的(相当于复杂的http协议),你只需要学习下汽车怎么开(相当于学习CGI协议)就可以直接开起来了
有了cgi协议,web服务后面的web应用可以调用非常简单的方法就可以处理http协议了
此时web程序的两大组成部分的开发如下
1、web服务:新增一个功能->把http协议解析的结果,按照cgi协议的规定给组织好
2、web应用:按照cgi协议的规定,去获取数据就可以,再也不用去管复杂的http协议了,此时遵循cgi协议的web应用程序也会被直接称为CGI程序
五、FastCGI的诞生
每一个动态请求:
web服务都会调用一次CGI脚本、产生一个进程,该进程则处理完一个请求后立刻退出
下一个请求来时再创建新进程。
此时的问题:在访问量很少没有并发的情况也行。但当访问量增大,并发存在,这种方式就不适合了,于是就有了FastCGI
FastCGI本质就是CGI协议,只不过是升级版,相当于一个常驻(long-live)型的CGI ,FastCGI协议规定:一个处理动态请求的进程处理完一个请求后不会关闭,而是可以继续处理下一个
注意:FastCGI与CGI一样都是协议,协议就是一份合同,是规定,并不是实实在在存在的东西,就好比是你寄快递,填写快递单的规则就是协议,是你跟快递公司之间的约定,你得遵守,双方才能看懂对方的意图才能按协议规定运转下去
六、php-fpm
-
1、php-frm是什么?
CGI 和 FastCGI 都只是一种协议和HTTP 协议一样位于应用层,与语言无关;
PHP-FPM 则是 基于 FastCGI 协议实现的一种具体的程序,从命名上你可以看出来php-frm全称(PHP FastCGI Process Manager)(http://php.net/manual/zh/install.fpm.php),即基于FaskCGi协议的进程管理器 -
2、那么 PHP-FPM 是如何工作的呢?
PHP-FPM 进程管理器有两种进程组成,一个 Master 进程和多个 Worker 进程。Master 进程负责监听端口,接收来自 Web 服务器的请求,然后指派具体的 Worker 进程处理请求;worker 进程则一般有多个 (依据配置决定进程数),每个进程内部都嵌入了一个 PHP 解释器,用来执行 PHP 代码。并且 php-fpm能根据访问的压力动态的唤起cgi进程和销毁以到达动态的调整cgi数量,这样可以有效的使用内存。 除此之外还有其它的一些优点,比如,fpm还可以平滑的重载php配置;由于fpm是使用Unix-Socket来和服务器通讯, 所以也不用再配置cgi端口;fpm有更好的状态输出和slowlog日志,502的时候能给出更多的错误细节。
-
3、PHP-frm不支持http协议,不能直接充当web服务!!!!!!!!!!!!!!!!!!!!
PHP-FPM 本身并不直接支持 HTTP 协议,它主要使用的是 FastCGI 协议。这意味着PHP-FPM并不能直接对外提供http协议的服务。通常它和 Nginx 或者 Apache 等 Web 服务器配合来使用。
HTTP 请求最先由 Web 服务器(如 Nginx 或 Apache)接收,然后由 Web 服务器通过 FastCGI 协议传递给 PHP-FPM来处理,如下图
简图
七 Nginx 服务器如何与 FastCGI 协同工作
Nginx 作为web服务,无法直接与 FastCGI 程序(例如php-fpm)进行通信,需要启用ngx_http_fastcgi_module模块进行代理配置,才能将请求发送给 FastCGI 程序(例如php-fpm)。
其中,包括我们熟知的配置指令:
fastcgi_pass 用于设置 FastCGI 服务器的 IP 地址(TCT 套接字)或 UNIX 套接字。
fastcgi_param 设置传入 FastCGI 服务器的参数。
对比一下nginx中负责将请求转发到另一个服务器或者进程的两条指令
1、proxy_pass:是处理 HTTP 或者 HTTPS 协议的请求,将请求转发到另一个 HTTP 或 HTTPS 服务器
2、fastcgi_pass: 指令是处理 FastCGI 协议的请求,特别针对PHP这一类的动态内容,将请求转发到 FastCGI 进程,
例如 PHP-FPM
之前我们已经介绍使用过过nginx的proxy_pass了,接下来看一下fastcgi_pass转发fastcgi协议的请求该如何配置
# 官网:https://www.php.net/manual/zh/install.fpm.php
# This is the origin nginx conf.
location ~ \.php$ {
try_files $uri = 404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
# You can replace it by
upstream php {
server 127.0.0.1:9000;
server 127.0.0.1:9001;
server 127.0.0.1:9002;
server 127.0.0.1:9003;
}
location ~ \.php$ {
try_files $uri = 404;
fastcgi_pass php;
fastcgi_index index.php;
include fastcgi.conf;
}
更多内容你可以到 PHP FastCGI 实例教程 (https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/)学习一些基本使用。
八、web框架又是个啥?
web程序的构成=web服务+web应用
最开始web服务与web应用之间就是通过http协议通信的
后来大家把http协议做了进一步的封装,诞生了用起来更简单的一些协议例如cgi、fascgi等
于是web服务在接收到http协议的请求后就会按照例如cgi这种协议进行二次封装,然后web服务会把封装好的结果扔给后面的web应用,并且得意扬扬地跟后面的web应用说,瞅瞅,全都是我web服务的功劳,才能让你web应用开发起来变得非常简单
web应用了之后点点头说,道理是这个道理,但是,我还不够简单,我虽然不用处理复杂的http协议了,我只需要处理看起来简单一点的cgi协议就行了,但是,帮人帮到底、送人上西天啊,能不能cgi协议都不用我处理了?????
web服务表示,我只能帮你到这了,你的这个请求我满足不了。
为了满足web应用要求更简单一点的需求,简单到任何协议都不想看,就想专心写业务逻辑,于是有人蹦出来说,这样,我们把web应用的开发再做一些细致的分工,分成上半部分与下半部分
1、上半部分
我来把web应用开发的上半部分代码给写好(这部分代码里包含了如何解析cgi等协议),并且我还把一些你们开发业务逻辑过程中经常要用到的一些重复性功能也都给你们写好
2、下半部分
然后你们所有web应用开发者就直接把我的这个代码拷贝过去,这样你们就只需要开发下半部分就可以了,如此,你们web应用开发程序用就连cgi协议都不用学习了,专心写业务逻辑吧
听到这里,聪明的同学应该懂了,这里说的web应用程序、web应用程序、web应用程序,的上半部分,就是web框架
框架是啥?如果把开发一款web应用程序比喻为建一所房子,web框架就是房子的骨架
我们平时开发web应用程序,都是这种抄的思想,上来先不管三七二十一,先把上半部分代码拷贝过来,然后功能就是实现了一半,剩下的就是编写业务逻辑就行。
有人说:能不能业务逻辑也不用写了?tmd,过分了哈少年,树叶过河全靠一股子浪劲啊你
九、python体系里的wsgi、asgi、uwsgi
9.1 先说web服务与web应用之间的协议=wsgi与asgi
1、WSGI,(WEB SERVER GATEWAY INTERFACE),Web服务器网关接口
它是专为python定制的,用于在Web服务器与web应用之通信的一种规范。
2、ASGI(Asynchronous Server Gateway Interface): 这是WSGI的异步版本,Django Channels等项目就是基于ASGI实现的。ASGI可以处理WebSocket、HTTP、HTTP2的需求,支持异步和长连接。(wsgi协议不支持websocket)
9.2 web服务之uwsgi服务与daphne服务
1、与web应用基于wsgi协议通信的web服务通常是uwsgi服务
2、与web应用基于asgi协议通信的web服务通常是daphne服务
9.3 uwsgi服务与nginx服务对接的协议:uwsgi协议
uWSGI协议,是uWSGI服务器与其他服务器(如Nginx)之间的通信协议,不是Web服务与Web应用之间通信的协议。
例如,你可能会在uWSGI服务器和Nginx服务器之间使用uWSGI协议,使得Nginx可以转发请求到uWSGI服务器,然后由uWSGI服务器与Web应用进行交互。
为什么uwsgi服务与python的web应用之间通信用的是wsgi协议,而uwsgi服务于nginx直接走的则是uwsgi协议
答:
1、web服务与web应用之间走wsgi协议:这是因为 WSGI 是 Python web 开发的标准协议,对于所有采用Python编写的Web应用程序,WSGI都是通用的接口标准。
2、当uWSGI与如Nginx这样的Web服务器通信时,它们使用的是uwsgi协议,这是因为在这种情况下,uwsgi协议比WSGI协议更高效。
总的来说,uwsgi 协议与WSGI协议在不同的层次上工作。WSGI 是应用程序与Python Web服务器间的接口,而uwsgi 是 Web服务器(uWSGI)与网络服务器(如Nginx)间的接口。这就解释了为什么uWSGI 服务器与 Django框架开发的web应用之间使用 WSGI 协议,而uWSGI 服务器与 Nginx 之间使用 uwsgi 协议。
9.4 daphne服务于nginx服务对接的协议:http协议
Nginx和Daphne之间通常使用HTTP/HTTPS协议通信,而Daphne与Web应用之间则使用ASGI协议通信。
9.5 php体系与python体系总结与对比
相同点:
uwsgi程序——–拉起——-python的web应用
php-fpm程序——拉起——-php的web应用
不同点:
1、uwsgi程序可以解析uwsgi协议,也可以解析http协议,所以uwsgi程序启动之后可以作为一个web服务用,并不是一定需要搭配nginx,虽然通常我们建议搭配nginx一起用
2、php-fpm程序启动之后,只能解析fastcgi协议,不支持http协议,所以php-fpm启动之后不能作为一个web服务用,一定要搭配像nginx一样的web服务用才行
9.6 nginx配置转发的三条指令
nginx用于将请求转给其他进程的内置指令(不需要为nginx额外安装包,默认支持)
proxy_pass:http协议、https协议
fastcgi_pass:fastcgi协议
uwsgi_pass:uwsgi协议
补充:之前你在nginx里配置proxy_pass也能转发给uwsgi服务,是因为uwsgi服务也支持http协议
问:为何我在nginx里用proxy_pass也能转发请给uwsgi服务?
答:因为你在uwsgi.ini可以配置开启uwsgi协议也可以配置开启http协议,甚至可以配置同时开启uwsgi与http协议
uwsgi服务都是支持的
问:如果nginx的后面是uwsgi服务,那建议用proxy_pass还是uwsgi_pass
答:当然建议uwsgi_pass,这样传输的才是uwsgi协议 ,才能利用上uwsgi协议的强大性能,之前的章节是egon故意用proxy_pass给你演示,目的就是告诉你,也可以,但并不代表是正确的用法
十、总结
其实说了这么多,无论如何组合使用,你始终记住3大关键点就行
1、nginx的转发指令有proxy_pass、fastcgi_pass、uwsgi_pass用于转发不同的协议
2、php-frm运行在fastcgi协议,对应nginx的fascti_pass指令
3、uwsgi可以运行在http、也可以运行在uwsgi,前者对应nginx的proxy_pass指令,后者对应uwsgi_pass指令
任何场景下,自己去对应就行,哦还有一条记住uwsgi协议肯定比http协议快,能用uwsgi则用uwsgi是正确的