背景:
1. 本人非科班,非IT/互联网行业从业人员,本文仅从较高层级的角度进行简单总结,涉及底层实现的内容尽量不提及,以免误人子弟。我尽量用浅显易懂的方式把问题说明白。如果有疏漏出错的地方,希望各位大神不吝赐教。各位有不明白的地方尽管找我交流。
2.涉及后端的代码都是用Python写的,只是用来辅助说明, 没必要理解。
一、 基本概念
- 什么是域名?什么是主机?什么是主机名?
我们已经对域名习以为常了,你可能会说www.sina.com.cn就是一个域名,因为我们习惯了这种叫法。
但是等等,你购买域名的时候商家会给你www这个前缀吗?不会。因为sina.com.cn才是域名。域名是唯一的。
那么什么是主机,主机就是这个域里面的其中一台主机。我们可以给它命名为www,也可以命名为news。
那么 www.sina.com.cn就是一个主机名,news.sina.com.cn也是一个主机名。sina.com.cn域下就有两台主机。 - 计算机是怎样与远程计算机通信的
计算机与计算机之间的通信实质上就是两个进(线)程之间的通信,客户端打开一个进(线)程,再打开一个端口,服务器同样有一个进(线)程和一个端口,再配合相关的协议,通过这一个出入口传输数据,计算机之间就可以通信啦!
当我们用浏览器打开一个网页,我们就相当于在本机上打开了一个浏览器进(线)程,并打开了一个端口,和服务器进行通信。
那么要怎么通过Internet准确找到我们想要进行通信的远程计算机呢?这时候我们就要通过IP地址来准确定位,每台公网上的物理主机都有唯一的IP地址。就像我们需要根据学号来准确定位一个学生一样。 - DNS服务器的作用
那么等等,你可能会问,我们平时输入网址时根本没有指定服务器的IP地址呀,怎么就可以通信了呢,因为有DNS服务器。
DNS服务器的作用就是用于域名解释,我们平时输入的网址例如:www.baidu.com,看得出来,并没有任何IP地址的相关信息,但是有DNS服务器帮我们找到了 .baidu.com域对应的IP地址,我们就不用烦心去记指定ip地址了。 - 怎么通过同一域名找到对应的主机
可能你又会问,既然同一域名通过DNS会被解释为同一IP地址,那么怎么识别同一域内不同的主机呢?没错,通过主机名(host),这时主机名的作用就出来了。希望你看到这里的时候还没忘记主机名的概念。 - URL的作用
我们能通过它来定位到Internet上的某个资源,它返回的内容可以是一段数据或者一个文件。 - 缓存的作用
从cpu到操作系统到浏览器都有缓存的概念。记着缓存就是就近取材,附近有的就肯定不会跑远的地方去拿了。(除非你指定说不要就近取材) - HTTP协议有什么用
超文本传输协议,我们在浏览器输入url的时候,如果要获得某个资源,必须遵循http协议。 - HTTP协议是在什么基础上实现的
HTTP其实只是众多协议中的一部分,我们还有FTP,HTTPS,FILE、上面的DNS协议等等等等。而且这众多协议也只是属于TCP/IP协议簇上的“某一层”而已。
HTTP是基于TCP/IP协议簇的。TCP/IP协议簇是经济基础,HTTP是上层建筑,经济基础决定上层建筑! - 请求是什么?响应是什么?
其实每次我们使用HTTP请求Internet上的资源的时候,浏览器都会发送一个请求到服务器。我们称之为请求报文。里面包含必要的信息。
你想让服务器干某件事,是不是必须让服务器知道你想要他干什么呢?
服务器理解了你的请求并返回你需要的资源这个过程就是响应。
二、具体实现过程
2.1 域名解释的过程
本机确实没有缓存的时候,才会经过TCP/IP各层,然后去各服务器获取相应IP地址。
2.2 我的博客是怎么部署的
这里为什么提我的博客部署呢?一是记录一下自己的部署过程,二是方便理解下面的内容。
我使用了 python实现了一个小博客。使用 nginx + gunicorn + sqlite部署了博客。
那么,这四者分别是什么角色呢?
nginx: web服务器。起到转发请求、缓存数据的功能。
假如我有很多主机,那么nginx就可以根据主机进行转发请求,把请求发送到
不同的主机里。如果只有一台主机,它也可以把请求分为静态资源请求和动态
资源请求,然后分别转发。
gunicorn:web服务器。负责接收nginx发来的HTTP请求,并把它转换为Python能够
识别的信息,且兼有进程管理功能。
python:能写后端的代码种类很多,这里以Python为例。它接收了gunicorn传来的请
求,然后让代码对请求进行处理,成功后返回一个响应并原路返回。
sqlite: 数据库。用于与Python之间的数据交换。Python有驱动及接口调用sqlite。现在我们
不关心它是怎么调用的。实际商用的话一般不用sqlite。
可能有同学会疑问,nginx 和 gunicorn的作用同样是web服务器,为什么要放一起,其
实这里的nginx更像一个路由的作用,负责分发请求,而不再是单纯web服务器了,可以叫它为反向代理服务器。而gunicorn呢,有点像网关,把http翻译一下交给Python处理。这里把它叫做wsgi服务器比较合适。
其实画个图就是这样而已:图片
其中:WSGI是一种应用程序接口规则,按照这种规则写的Python代码,gunicorn才能解读。同样地,经gunicorn解释的http请求,要满足WSGI规范才能被Python解读。
2.3 后端处理
后端处理其实涉及的内容也是非常复杂的,特别是数据库设计及优化,通常会有架构师及数据库工程师把关。凭我目前水平也根本说不清楚,我利用我写过的博客为例,尽量简单明了把关键内容说明白。这里只大概说一下MVC流程吧。
2.3.1 Model:
Model就相当于是数据,如果你在阅读下文时觉得“Model”难以理解,可以先把它替换成“数据”两个字。话不多说,看图:
我解释一下。这是我在刚学Python的时候打算搭建博客时,设计的Model。
看图,有那么几个Model对象:Article(文章),Comment(评论),User(用户),UserProfile(用户档案),Vote(点赞)。
这些对象就是我们在MVC中操纵的Model,那么画个图我们就能操纵Model了?当然不是,请看:
看绿色字,是不是看到了熟悉的单词呢?Article,Comment,UserProfile。那么我们把代码写出来就可以了吗?当然不是,我们需要把这些Model相关的信息写入数据库。过程略去不说,反正你知道要写入数据库就行了。下面我们只关注Article。
好了,假设我们已经把这些写入数据库了,那么它们在数据库里是怎样表示的呢?先说一句:是以 表-条目 的形式的方式表示的。看图:
这是Article的表,里面的条目就是一个个具体的Article!自己观察一下表头,跟刚才的代码里的Article之间存在什么关系呢?
好了,至此,我们的Model已经准备好了!就是说数据已经准备好了,让客户端的请求来得更猛烈些吧。
2.3.2 Controller
Controller接收到gunicorn发来的请求,根据请求提取Model里相关的数据,并告诉View:“喂,我这有个数据,把它展示到页面上吧!怎么展示你说了算。”
代码的意思大概是,我们的代码接收了一个客户端的请求,该请求定向到了我的博客主页,于是我把数据库里面的Article都取了出来,并命名为articles.然后把articles传给了一个叫blog/blog.html的文件。我们记着articles这个单词往下看。
这里注意一点:
我只是使用Python往数据库写入数据,但是数据库的数据即Model本身是非常独立的,被写入的数据同样可以被其他语言的controller调用,例如JAVA,Ruby等。
2.3.3 View
blog.html:“OK,收到,我把articles放到html里面展示出来,加点CSS,变漂亮一点!”
这是部分HTML代码截图。说明都在图上了,不赘述了。
至此,我的Article Model 旅程算是结束了。
现在一个(漂亮的?)页面就已经就绪了!就差把它弄到浏览器让我们看见了!
其实还有一步,得把这个带有数据的页面作为HTTP响应返回给gunicorn!其实我在controller已经做了这一步了。这里不用纠结细节。知道controller会接受请求,传递数据和返回请求就行了。
好了,MVC的简绍也就到此结束。
这时候...HTTP响应原路返回,一路就到了浏览器啦
3.浏览器页面处理
浏览器根据响应做出相应的动作,例如,响应的是一个html页面,那么就会对html页面进行解释,遇到需要再次请求的地方,例如一个css,一个JavaScript,则会再次向服务器发起请求。
然后浏览器会对页面进行文档流的布局,分析元素的大小,内外边距,是内联元素还是块级元素,是否占用文档流空间等,对HTML元素进行逐个布局(渲染树)。遇到需要执行js的节点会执行相应js程序。
那么如果响应不是一个html页面呢?例如是一个重定向响应,那么浏览器会根据相应报文的响应头部信息确认重定向的位置。如果是一个404响应呢,那你很有可能看到404页面。
三. 总结:
话不多说,一图流吧,主要是对HTTP报文的传输过程进行总结(当然是根据这篇文章的一图总结了,其他不在此文内容的细节请忽略。)
有点大,点击链接吧。图片在这里