上一章Java web学习(0)博主根据个人情况定制的java web学习路线和学习方法讲了 自己学习Java的路线,还有学习的一些方法和资源,这一章作为真正的前启,细细的理一下关于web服务器还有web框架的思想和原理。
你打开浏览器输入链接就显示出了精美的网页,这其中是什么原理?
为什么有那么多的web框架,它们有什么不同?
让人眼花缭乱的web框架怎么提取相同的部分,快速掌握其核心?
这篇博客博主根据个人的理解总结了下。
上图中可以概括出以下过程
http://www.baidu.com
三个角色:
菜鸟教程讲的很清楚了。
这一步骤的主要目的是为了匹配路径,比如说我写了个网页部署在了服务器上,域名是www.hhh.com
,然后里面有一个应用对应的路由是/hello,因此它能响应的也只有www.hhh.com/hello
,而对于www.hhh.com/hhh
这个url就无法响应。这一步骤一般是由服务器软件实现的,如tomcat、nginx、IIS,或者CGI程序。
用户传入的任何数据,get方式、delete方式一般不包含请求body,请求数据都放在url中作为参数传递,如www.baidu.com?name=123
,post方式、put方式一般将数据放在请求body里面,数据的格式会在header的content-type里描述,一般为
form-data content-type一般是 multipart/form-data,这是最传统的表单形式,参数可以是字符串、数字、文件等,但是他们都会在传输时按照具体的格式转为字节流。
form-data在服务器端呈现的格式:
application/x-www-form-urlencoded会把参数向get方法那样编码如name=123&age=234
,虽然参数还是在body,但是可以使用简单的方法处理。
x-www-form-urlencoded服务器的处理(代码是node.js):
这里把请求的url和请求body的数据进行了合并,再使用和处理get请求一样的方法进行解析。
raw类型,这是一个大类,里面还有细分的类型:
最常用的是json,较老的是xml。
binary就是文件
可以是任意文件,浏览器或者http client会自动根据文件类型发送对应的mine类型,
这个很类似switch语句
switch(method){
case 'GET': doGet();
break;
case 'POST': doPost();
break;
case 'PUT': doPut();
break;
case 'DELETE': doDelete();
break;
// ... 匹配更多的请求方法
}
先根据请求方法匹配再根据url匹配(/
指的是根路径,如表示http://www.hhh.com/
,如果是具体的hello app也可以是http://www.hhh.com/hello/
)
在spring boot中:下例是 GET /hello 或者 GET /hi 就可以进行请求
在nodejs中,则更加简明,下例是GET /login
在flask中,可以感觉到在mvc思想下的程序controller
的实现都是大同小异
有一些框架会把路由单独出来,个人感觉这种方式虽然更麻烦一点,但是更易于维护,可以简化框架的结构:
如django,django是mtv结构,model-templete-view,其中view是具体的业务逻辑层。至于controller被简化成了一个路由文件:
这里hello_views.index就是具体的业务逻辑层的函数,可以重载http方法函数如def get(self, request)
,或者根据request.method来进行判断。
虽然各种框架对这个路径和请求方法的处理各不相同,但是抛开表面的花里胡哨,其实都可以用if else if
来取代,那为什么要分成这样呢。
1、可扩展性
代码应该可以在不修改或者少修改原有代码的基础上新增功能。
2、易维护
代码应该条理清晰,层次分明。易于上手,方便团队分工协作。
3、易于测试
将controller层和service层进行严格的分离之后,就可以对service层每一个方法进行单元测试。
4、易于重用
相似的业务容易抽出service代码来进行复用。
从个人角度而言,如果一个项目只写一次,项目也不大,以后也不维护,只有我一个人写,那么使用框架并无必要。因为框架在带来优点的同时也带来了复杂性。
PHP一个文件实现的功能,java可能要写十几个文件。所以说很多外包项目使用PHP作为开发语言。
这是最后一个部分,经过这个步骤之后,数据给发送给用户的电脑,被浏览器解析,然后呈现出效果。
在Django中对这一过程可以很好的实现
字符串数据hello django
通过HttpResponse封装后变成http响应报文,发送给用户。
在flask中这一过程被简化了:
实际上这个Hello World!
还是经过了框架的处理才封装成HttpResponse对象,从而形成http响应报文,返回给用户。
nodejs中也是
要说明一点nodejs的reponse对象是一开始就挂载上的,这和django很不同,django是经过了构造。
这里用最常见的登录注册功能实现来举例mvc结构的处理过程,其中并没有提到v层,因为现在使用前后端分离的技术越来越普遍了,view完全可以交给前端独立完成。
对于controller层,我们可能希望它尽可能简单,因为这样service就可以更加独立,一旦需要修改功能,我们不要改动controller层,只要改动service层,并且这样就可以对每个独立的功能进行完善的单元测试。controller只起到配置路由的作用。有些时候会把数据校验也放在controller里面,但是并不推崇这种方式。
model层是数据库模型、数据库操作,数据库的表和类模型通过一些orm框架的映射实现了关联,如hibernate、mybatis、还有nodejs的mongoose等。通过orm框架,表结构被轻松的映射到了类对象中,方便了调用。
不管是哪一种语言的web框架,其核心都是一致的,那就是以http协议为核心,围绕着http请求和http响应这两方面做文章。至于衍生的数据持久化(cookie session 数据库 等)只是存储手段罢了。
如果要理解好http协议,没有什么比实现一个自定义的http client客户端和http server服务器更好的方法了。
ps: 请随意转载
ps: 如有错误,请评论指出