Java后端自顶向下方法——一切从HTTP开始

Java后端自顶向下方法——一切从HTTP开始

(一)为什么要先学HTTP请求

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。很显然,HTTP协议是客户端与服务端之间通信的一个重要桥梁。可见其重要性。
在这里插入图片描述
在这个技术日新月异的时代,1991年就已经发布的HTTP协议一直未被淘汰,也一直担任着传递请求和响应的重要任务。对于我们后端开发者来说,我们从客户端获取的数据和发送给客户端的数据,十有八九要借助HTTP协议来完成,所以我们就从HTTP协议开始学习。

(二)HTTP协议的特点

了解一下HTTP协议位于应用层:
在这里插入图片描述
我们先来看看神奇的HTTP协议有哪些特点:

  1. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  2. 灵活:HTTP允许传输任意类型的数据对象,正在传输的类型由Content-Type加以标记。
  3. 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,断开TCP连接。这种方式在请求多个资源时,建立TCP连接会浪费较多的时间(HTTP1.1版本支持了持久连接,改善了这个情况)。
  4. 无状态:HTTP协议是无状态协议,对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大(cookie的出现打破了这一局面)。

由此可见,HTTP的劣势在一次次的更新中不断被改善当然,我能猜到你可能现在是一脸懵,在这里你可能不需要知道每个特点究竟是什么意思,咱们暂且混个脸熟,在未来我们对HTTP协议的使用过程中,这些你都会自己慢慢体会到。

(三)HTTP之统一资源定位符

什么是统一资源定位符?

HTTP使用统一资源标识符(Uniform Resource Identifiers,URI)来传输数据和建立连接。URL是一种特殊类型的URI,包含了用于查找某个资源的足够的信息。URL,全称是UniformResourceLocator,中文叫统一资源定位符,是互联网上用来标识某一处资源的地址。

说人话说人话!用专业名词来解释专业名词可不是我的风格!其实这个URL我们天天都能看见,不信你就擡头,看你浏览器的地址栏,你就知道我在说什么了。这个地址栏里的地址就是所谓的统一资源定位符了。我随便来举个例子,现在我在Google里搜索“http”,然后地址栏里变成了

https://www.google.com/search?newwindow=1&sxsrf=ALeKk026EAz0wpwdHgaITghcVcbrZXPt8g%3A1587289292913&ei=zBycXsSbN6S38QOLxriQCw&q=http&oq=http&gs_lcp=CgZwc3ktYWIQAzIHCAAQgwEQQzICCAAyAggAMgIIADIFCAAQgwEyAggAMgIIADICCAAyAggAMgIIADoECCMQJzoGCAAQBxAeOgUIABDNAjoGCAAQBRAeOgQIABBDUMSV3CBY9JncIGDXntwgaAJwAHgAgAHWAYgBkAeSAQUwLjUuMZgBAKABAaoBB2d3cy13aXo&sclient=psy-ab&ved=0ahUKEwjEsdazmfToAhWkW3wKHQsjDrIQ4dUDCAw&uact=5

你现在可以想想我们是怎么样通过这个URL获得这个网页的内容的。首先,资源都是保存在服务器中的,那么我们的浏览器必然要告诉服务器,我需要哪个资源?这样服务器才知道要发送给你什么资源啊。显然,这个URL就代表了一种资源。细心的你可能发现,这个URL里面怎么又那么多乱七八糟的东西,比如?&=-%/:之类的,那么下面我们就来讲一讲URL的组成。

  1. 协议部分:该URL的协议部分为“https:”,这代表网页使用的是HTTPS协议(是一种更加安全的HTTP协议,现阶段我们就把他当HTTP协议来看)。在"HTTPS"后面的“//”为分隔符。
  2. 域名部分:该URL的域名部分为“www.google.com”。他会被DNS服务器解析为IP地址,所以也可以直接使用IP地址代替域名使用。
  3. 端口部分:(非必须)跟在域名后面的是端口(我们这个URL中没有写端口),域名和端口之间使用“:”作为分隔符。如果省略端口部分,将采用默认的80端口。
  4. 虚拟目录部分:(非必须)从域名后的第一个“/”开始到“?”前为止,是虚拟目录部分,是资源在服务器所在的位置。该URL中的虚拟目录是“/search”。虚拟目录的根目录会映射到服务器的特定真实目录下。当我们使用Restful API时(后面会讲)这个虚拟目录又有新的理解。
  5. 锚部分:(非必须)从“#”开始到最后,都是锚部分。这个东西不算特别重要,暂时先不讲。
  6. 参数部分:从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。参数以键值对的形式出现,即key = value。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。该URL中参数很多,大家可以依次找找看,增加理解。

这样我大概解释完了这个URL的组成部分,相信大家都已经理解了,因为这确实非常简单。在以后的学习中,这个东西将常伴你左右。

(四)HTTP之Request

讲了这么多,终于讲到向服务器发出的HTTP请求的内容了。首先我们先来看看一个标准的HTTP请求里面有些什么内容。

在这里插入图片描述
第一部分:请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本。

第二部分:请求头部,紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息。

第三部分:空行,请求头部后面的空行是必须的。即使第四部分的请求数据为空,也必须有空行。

第四部分:请求数据也叫请求体,可以添加任意的其他数据。在这个例子中的请求数据为空。

当然,直接看这些概念肯定会比较抽象,我们再来举个例子。

POST /test HTTP1.1
Host:www.abc.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive

name=TOM&age=21

第一部分:请求行,第一行明了是post请求,以及http1.1版本。
第二部分:请求头部,第二行至第六行。标明了附加信息。
第三部分:空行,第七行的空行。
第四部分:请求体,第八行。

请大家仔细观察这个HTTP的request请求,有没有发现一些熟悉的东西?里面是不是有一部分东西似乎在之前提到的URL中出现过?观察完之后,试着能不能找出这个request中包含的URL是什么。如果忘记了,赶紧回去看看上面的图。

没错,就是:http://www.abc.com/test
很显然,请求头中的Host就对应了URL中的域名,请求行中的URL部分实际上是真正URL中的虚拟目录部分。什么?你问为什么请求体中的参数不见了?你一定是看见了“name=TOM&age=21”了吧,这当然不是我写错了。这涉及到我们接下来要讲的HTTP请求的请求方式。

(五)HTTP之请求方式

首先我们看看HTTP到底支持哪些请求方式,下面列举了一些常见的请求方式。

GET     	请求指定的页面信息,并返回实体主体。
HEAD     	类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。
POST     	向指定资源提交数据进行处理请求,数据被包含在请求体中。
PUT     	从客户端向服务器传送的数据取代指定的文档的内容。
DELETE      请求服务器删除指定的页面。
CONNECT     HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS     允许客户端查看服务器的性能。
TRACE     	回显服务器收到的请求,主要用于测试或诊断。

其中,我们最常用的,是POST、DELETE、PUT、GET这四个请求方式。他们分别对应了四种基本操作:增删改查。但是有一点非常关键,这种规范只是一种人为的约定而已,这四种请求方式的名字和他们的功能对应关系并不是绝对的,具体对请求的操作是服务端书写控制器的时候才实现的,换句话说,我们在书写Restful API时,当然可以用get请求来表示删除数据,也可以用post请求来表示查询数据,虽然这会让人觉得怪怪的。这是初学者必须要注意的一点,非常重要!!!具体的用法我们会在下面和Restful API一起讲。

PS:网上有许多博客都着重写了GET和POST的区别,主要关注点是GET请求的参数放URL中、POST请求的参数放请求体中。我也特意查了相关的资料,HTTP协议好像并没有这种规定。这应该只能算是一种约定。还有就是关于URL的长度限制问题,HTTP协议也未提及,这个限制可能是来自于浏览器和服务器,具体限制长度是多少,要具体情况具体分析。

(六)HTTP之Response

Http Response包括三个部分:响应状态行,响应头和响应体。第一行是响应状态行包括Http版本+响应状态,以空格分隔。从第二行开始是响应头,包含若干个键值对,每个键值对占一行。后面空一行,接着是响应体。
在这里插入图片描述
乍一看,这Response和Request区别也不大。首先我们可以想想,作为一个HTTP响应,与HTTP请求相比,有哪些部分是没必要加上的?首先,虚拟地址不需要。服务器已经开始返回数据了,证明他已经知道了需要访问哪个资源了,这个虚拟地址也没必要再返回给客户端了。同理可得,请求方法也就不需要了。所以我们在学习过程中,不仅要学会协议的内容,还要思考协议为什么要这样设计。下面我放一个Request来对比一下,看看是不是这样。
在这里插入图片描述
很显然,上面的Response还多了一个“200 OK”的状态码,这个是干什么用的?接下来就来讲这个。

(七)HTTP之状态码

状态码由三位数字组成,第一个数字定义了响应的类别,共分五种类别:

1xx:指示信息–表示请求已接收,继续处理
2xx:成功–表示请求已被成功接收、理解、接受
3xx:重定向–要完成请求必须进行更进一步的操作
4xx:客户端错误–请求有语法错误或请求无法实现
5xx:服务器端错误–服务器未能实现合法的请求

我相信你们肯定在上网时看见过这种页面:
在这里插入图片描述
现在,你终于知道404是什么意思了吧。他是HTTP的其中一种“标准回应消息”(HTTP状态码),此消息代表客户端在浏览网页时,服务器无法正常提供消息,或是服务器无法回应且不知原因。通常是因为用户所访问的对应网页已被删除、移动或从未存在。404也是互联网上最常见的错误之一。

当然,我们没必要把所有的状态码全都背下来,很困难也没必要,因为他们实在是太多了。下面我列出几个最常用的,剩余的我们可以遇到之后再问问Google。

200 OK                        客户端请求成功
400 Bad Request               客户端请求有语法错误,不能被服务器所理解
401 Unauthorized              请求未经授权
403 Forbidden                 服务器收到请求,但是拒绝提供服务
404 Not Found                 请求资源不存在
500 Internal Server Error     服务器发生不可预期的错误
503 Server Unavailable        服务器当前不能处理客户端的请求,一段时间后可能恢复正常

状态码存在的必要是当客户端收到请求,可以通过状态码快速的得知数据传输的情况和获取资源的情况。在后面的开发中我们会讲到,我们可以自定义错误类型,也就是说我们可以设计自己的状态码。

(八)HTTP与Restful API

如果我没记错,前面我不止一次提到了这个所谓的Restful API,那这是个什么东西?
在这里插入图片描述
实际上,这东西是一个叫Roy Fielding的人的毕业论文,这哥们参与过设计HTTP协议。大家都知道,过去网页设计是前端后端融在一起的,比如PHP,JSP等。但是近年来移动互联网的发展,各种类型的Client层出不穷,RESTful可以通过一套统一的接口为 Web,iOS和Android提供服务。另外对于广大平台来说,它们不需要有显式的前端,只需要一套提供服务的接口,于是RESTful更是最好的选择。
在这里插入图片描述
上面那段话不理解没关系,以后你会慢慢理解的。其实,Restful是个很简单的东西,相当于一种架构或是一种规范而已。网上许多博客都把他复杂化了,让初学者很难去理解他究竟是什么、怎么用。我曾经在学习时看见过这样的三句话,非常完美的概括了Restful API:

看URL就知道要什么
看http method就知道干什么
看http status code就知道结果是什么

现在你可能还看不出这三句话到底妙在哪里,所以我们先慢慢一点一点讲。

首先,我们要明确的一点是,请求的目的是操作资源。而Restful是面向资源的,也就是说URL中的内容代表的是一种资源,从语言上来看,这应该是一个名词,比如书、杂志、学生或者是汽车等等。但是,众所周知,作为一个请求,只有名词是肯定不行的,还要有相应的动词做支撑,比如,查询一本书,添加一本杂志,删除一个学生等等,这样才是一个完整的请求,也就是所谓的动词+名词。

那么,名词已经有了,动词该怎么表示呢?别忘了,除了URL之外,我们还有请求方式。前文提过,POST、DELETE、PUT、GET四个请求方式分别对应了四种基本操作:增删改查,这东西终于有用武之地了。加上相应的动词之后,整个请求就算是拼装完了。

下面我们来看一个小例子,当代大学生最喜欢的案例之一:图书管理系统。

咱们先假设我们项目的域名是example.com,我们来完成图书的增删改查的Restful API设计。比如我现在要查询图书,那么请求方式为GET,请求的URL可以设计为http://example.com/library/book,当然,这个URL可能无法精确指定我们具体想查哪一本书,所以我们就把他当做是查询所有的书,服务器将会返回一个书的集合,里面包括了所有的书。那么问题来了,我现在就想查询一本指定ID的书,该如何设计呢?别忘了,除了虚拟地址外,我们还有参数没用呢。

所以,我们要为这个API加上一个参数,使他变成一个新的API,我们可以这样设计http://example.com/library/book?id=?,这里的?就填你要查询的ID就行,如果不填,那就相当于上面那个API,也就是查询所有书。

同理,我们就可以设计出这个项目需要的所有的API了,我们以请求方式+请求URL的方式来展现一下。

GET http://example.com/library/book	          查询所有书
GET http://example.com/library/book?id=k      查询ID为k的书
DELETE http://example.com/library/book?id=k   删除ID为k的书
PUT http://example.com/library/book?id=k      修改ID为k的书
POST http://example.com/library/book?id=k     添加ID为k的书

通过这个小案例,大家应该已经明白了如何去设计Restful API了,那么HTTP的基础部分就到此结束了。

2020年4月21日

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章