看问题要看到本质:从Web服务器说起

2019 年 6 月 21 日 码农翻身

这是个很长的故事, 让我们从Web服务器来开始。


Web服务器是个挺简单的东西,工作很简单,在80端口上监听,解析客户端发过来的HTTP的请求, 然后把相对应的HTML文件、Image等返回给客户端就可以了。 像这样:


这就是一个静态内容服务器,所谓静态内容,就是服务器端的内容如HTML不会变化,每次请求都是一样的。除非人们手工改了它。


实现这样一个“玩具Web服务器”并不难,只要能了解服务器端Socket编程就可以了, 主要工作是编程处理HTTP协议的细节。



动态内容



但是如果想再往前走一步,让Web服务器能产生动态内容,那就难了。


比如说来了一个HTTP请求,在其中携带者用户名和密码,要求你去数据库做一个查询,看看用户是否存在。


POST  /login

user=xxxx&pwd=xxx


这个静态的Web服务器就搞不定了,它根本,也不应该去查询数据库。


怎么办呢?你可以用某种语言(比如C语言)写个程序, 来查询数据库,假设这个程序的名字叫db-query。


可是你将面对非常棘手的问题:  Web服务器是个进程,db-query也是个进程,这俩货之间怎么通信呢?


(友情提示,下面内容略显枯燥,可跳过)


首先是参数的传递,一种办法是这样:对于每个动态请求,Web服务器进程创建一个db-query的子进程,然后通过环境变量把参数传递过去。


web服务器:

setenv("QUERY_STRING","user=xxxx&pwd=xxx")


db-query子进程 :

param = getenv("QUERY_STRING")。


下一个问题:db-query这个子进程获得了用户名和密码,查询了数据库,怎么把查询结果返回给浏览器?


有个很巧妙的办法!


每个程序都有所谓的标准输出(STDOUT),db-query只要调用printf这个函数,数据就会输出到STDOUT,我们就可以在黑乎乎的控制台上看到了数据输出了。


但是输出到控制台是万万不行的,我们得输出到socket才可以发回浏览器。


每个浏览器和服务器的连接都是一个Socket, 每个socket都有一个文件描述符fd, 如果把查询数据库程序db-query的STDOUT重定向到那个fd,会发生什么?


没错!db-query的所有输出都直接发送的客户端的socket了,Web服务器可以撒手不管了!


当然,如果浏览器要看到的是HTML页面, 那db-query这个程序就需要输出HTML了。


这种方式就就是大名鼎鼎的CGI,当你看到网址中有cgi-bin字样的时候,很有可能就是用CGI实现的。  只要遵循CGI协议, 可以用任何语言来实现动态的网站。


这是人类迈出的一大步,有了这一步,才能在网上购物,办公,社交,聊天......  你才能看到我这篇文章(嗯,也许腾讯把微信公众号的文章都静态化了, 请了解详情的同学告知)


但是,CGI是非常复杂和笨拙的, 主要体现在:


第一,对每个请求,都得创建一个子进程去执行,这是个非常大的开销。


第二,对程序员来说,编程极为痛苦,要操作环境变量,还需要直接在编程语言中输出HTML!


麻烦不麻烦,难受不难受,上个世纪的程序员苦逼不苦逼?



Servlet



怎么才能跳出苦海?必须得做到关注点的分离


程序员的关注点是:拿到Http 请求中的数据,执行业务, 然后输出Http 响应。 别的什么环境变量,重定向,别来烦我!


那就简单了,让程序员写个类,里边是业务逻辑, 然后我们想办法构建一个HttpRequest对象和HttpResponse对象,传递给程序员的类让他使用不就行了?


谁来创建这个HttpRequest和Response 对象,  然后调用程序员写的类?


静态Web服务器表示我不愿意,我就想管好我这一亩三分地,把静态内容给大家服务好。


Tomcat已经迫不及待地要上场了,我来我来。码农朋友们,我送给你们一个规范,叫Servlet, 你们按照Servlet的规范来写程序,放到我这里运行,别的什么都不用管了。


程序员很高兴,只需要写简单的Servlet就行了,HttpRequest和HttpResponse对象由Tomcat来创建,可以从HttpRequest中获得Header, Cookie, QueryString 等信息, 从HttpResponse中获得输出流,直接向浏览器输出结果, 简单又直接。


Tomcat还郑重向大家声明:对于每个请求,我只会用一个线程来出来,线程的开销可比进程小多了。


对于那个在代码中混杂HTML的问题怎么处理?


 Tomcat也有办法, 可以在HTML混杂代码!这就是JSP。执行期其实会被编译成Servlet。


(码农翻身注:请移步《JSP:一个装配工的没落》)


你看,责任分离了,每个人只要办好自己的事情就好。


(注:实际上,我们不会在Servlet中写业务逻辑, Servlet现在通常是一个通往框架的入口。)


WSGI


CGI表示不服:遵循我的协议,任何语言都可以来实现动态网站,你Servlet只是Java规范,不管别的语言了?


Servlet规范确实没法跨语言实现,那要是Python也想做动态Web网站,该怎么办?


既然已经认识到动态网站的本质了, 可以采用类似的思想来处理嘛! 我们为Python也定义一个规范,叫做WSGI (Web Service Gateway Interface)。


让程序员写个类或者函数(称为wsgi application),在其中实现逻辑。让某个动态服务器(称为wsgi server)把Http Request和Response传递给它,就可以执行了。


但是Python表示:我不喜欢你们Java 那一套啰里啰嗦的类,HttpRequest 不就是一些key value吗?放到我钟爱的dict中多好 !我把它叫做enviroment, HttpResponse也没必要,直接用函数的返回值(确切说是一个可迭代对象)就好。


看看,是不是和Java 的Servlet 很像?(当然,忽略了很多细节。)


从本质上来说,都是为了关注点的分离:


1. 用一个动态内容服务器(wsgi server,Tomcat等)来接受并且封装HTTP 请求,降低程序员的负担。


2. 程序员只需要遵循约定(servlet,wsgi)就可以轻松实现自己的业务,不用关注系统的处理细节。


如果你先学的Java,通过Servlet理解了动态内容网站的本质和解决问题思路,再看到Python的wsgi,一眼就能看透,学起来飞快,反过来也是如此。


Web服务器的例子还比较简单,但是也体现出了这个道理:遇到问题要深度思考,努力看到本质,这样才能举一反三。



码农翻身公众号开放投稿,可能是全网最高片酬:

用故事讲技术 ,稿费1000

技术/职场/感悟/面试等,稿费700

翻译类文章,每千字200

详情猛戳: 可能是全网最高片酬,速来!


登录查看更多
0

相关内容

Web Service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。Web Service是自描述、 自包含的可用网络模块, 可以执行具体的业务功能。
【干货书】现代数据平台架构,636页pdf
专知会员服务
250+阅读 · 2020年6月15日
Python导论,476页pdf,现代Python计算
专知会员服务
254+阅读 · 2020年5月17日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
115+阅读 · 2020年5月10日
【SIGMOD2020-腾讯】Web规模本体可扩展构建
专知会员服务
29+阅读 · 2020年4月12日
TensorFlow Lite指南实战《TensorFlow Lite A primer》,附48页PPT
专知会员服务
68+阅读 · 2020年1月17日
Keras作者François Chollet推荐的开源图像搜索引擎项目Sis
专知会员服务
29+阅读 · 2019年10月17日
渗透某德棋牌游戏
黑白之道
12+阅读 · 2019年5月17日
Kali Linux 渗透测试:密码攻击
计算机与网络安全
15+阅读 · 2019年5月13日
PHP使用Redis实现订阅发布与批量发送短信
安全优佳
7+阅读 · 2019年5月5日
基于Web页面验证码机制漏洞的检测
FreeBuf
7+阅读 · 2019年3月15日
百度开源项目OpenRASP快速上手指南
黑客技术与网络安全
5+阅读 · 2019年2月12日
如何用GitLab本地私有化部署代码库?
Python程序员
9+阅读 · 2018年12月29日
我是一个爬虫
码农翻身
12+阅读 · 2018年6月4日
推荐一些适合小白练手的Python项目
数据挖掘入门与实战
6+阅读 · 2018年5月17日
码农日常工具推荐
架构文摘
4+阅读 · 2017年9月26日
Bidirectional Attention for SQL Generation
Arxiv
4+阅读 · 2018年6月21日
Arxiv
5+阅读 · 2018年5月1日
VIP会员
相关VIP内容
相关资讯
渗透某德棋牌游戏
黑白之道
12+阅读 · 2019年5月17日
Kali Linux 渗透测试:密码攻击
计算机与网络安全
15+阅读 · 2019年5月13日
PHP使用Redis实现订阅发布与批量发送短信
安全优佳
7+阅读 · 2019年5月5日
基于Web页面验证码机制漏洞的检测
FreeBuf
7+阅读 · 2019年3月15日
百度开源项目OpenRASP快速上手指南
黑客技术与网络安全
5+阅读 · 2019年2月12日
如何用GitLab本地私有化部署代码库?
Python程序员
9+阅读 · 2018年12月29日
我是一个爬虫
码农翻身
12+阅读 · 2018年6月4日
推荐一些适合小白练手的Python项目
数据挖掘入门与实战
6+阅读 · 2018年5月17日
码农日常工具推荐
架构文摘
4+阅读 · 2017年9月26日
Top
微信扫码咨询专知VIP会员