Java网络编程-HTTP协议

HTTP协议的定义

这篇文章暂时不研究HTTP底层的TCP/IP的握手和挥手过程,只从表面的交互流程分析HTTP协议。php

HTTP英文全称是Hypertext Transfer Protpcol,也就是超文本传输协议。HTTP是一个标准,定义了Web客户端如何与服务器对话以及数据如何从服务器传回到客户端。在平常开发和使用过程当中,HTTP常常被认为是一种用于传输HTML文件和文件中内嵌的图片的协议或者手段,实际上HTTP是一种通用的网络数据传输格式,它的传输内容不只仅局限于HTML文件或者图片,也能够用来传输Microsoft Word文档甚至是Windows的exe文件等等,全部能够用字节序列表示的数据均可以使用HTTP进行传输。html

HTTP经过TCP/IP进行数据传输,若是忽略底层的TCP协议的握手和挥手的细节,对于从客户端到服务器的每个请求和请求的响应,在HTTP1.0有下面几个步骤:java

  • 一、默认状况下,客户端在端口80开启与服务器的一个TCP链接,固然也能够指定其余的端口。
  • 二、客户端向服务器发送消息,请求指定路径上的资源。一个HTTP请求包括一个首部,可选项包括一个空行和此次请求的数据。
  • 三、服务器向客户端发送响应。响应以响应码开头,接着是包含元数据的首部,可选项包括一个空行以及所请求的文档数据或者错误信息。
  • 四、服务器关闭TPC链接。

在HTTP1.1(目前最经常使用的就是HTTP1.1)以及之后的HTTP版本中,能够经过一个TCP链接连续发送多个请求和接收多个响应。也就是说,上面的1和4步骤中间的2和3步骤能够反复执行屡次。另外,HTTP1.1中,请求数据和响应数据能够分块发送,提升了扩展性。nginx

HTTP请求方法

HTTP中定义了多种请求方法,用于标识当次请求须要完成什么类型的操做,经常使用的HTTP请求方法有GET、HEAD、PUT、POST、PATCH、TRACE、OPTIONS、DELETE。ajax

HTTP请求方法 描述 是否安全 是否幂等
GET 一般用于请求服务器获取某个资源
HEAD 相似于GET,可是响应结果中不包含响应体,只包含协议信息和首部,一般用于测试资源是否存在或者是否被修改 -
POST 客户端向服务器提交数据(支持HTML的表单数据),可能会致使新的资源的创建或者已有资源的修改
PUT 从客户端向服务器传送的数据取代指定的文档的内容(所有取代)
PATCH 客户端向服务器传送的数据取代指定的文档的内容(部分取代)
TRACE 回显客户端请求服务器的原始请求报文,用于"回环"诊断 -
OPTIONS 请求服务器获取服务器支持的各类功能,能够询问服务器支持什么类型的HTTP方法,通常用于性能测试 -
DELETE 请求服务器删除指定的资源

上面说到的"是否安全"的选项是"是",意味着使用该种HTTP请求方法不会发生任何数据的修改或者更新动做,也就是请求屡次也不会影响到资源的状态。若是"是否幂等"的选项是"是",意味着使用该HTTP请求方法请求屡次HTTP调用,不管调用多少次,请求结果或者资源的状态是同样的(能够理解为只有首次调用是真正修改了资源的状态,从第二次调用开始后面的调用只获取到第一次调用的结果)。HTTP方法的安全性和幂等性是咱们在设计HTTP接口时候须要重点考虑的两个因素。编程

值得注意的是:上面提到的POST和PUT方法的功能能够理解为相同的,二者的主要区别在于POST不是幂等的,而PUT是幂等的。在目前的Web开发中,POST方法已经被滥用,通常不多人会使用PUT,除非是推崇RESTFUL风格编程。PUT方法和PATCH方法的功能相似,都是用客户端请求的数据去替换掉服务器中指定文档中的内容,不过PUT方法是所有替换,而PATCH方法是部分替换。json

PS:上面的方法只是HTTP协议中的请求方法的一些规范,没有硬性规定必定要遵循。跨域

常见的HTTP状态码

JDK中常见的HTTP状态码能够在类java.net.HttpURLConnection中找到,总结一下以下:浏览器

状态码 状态码消息 含义 HttpURLConnection中的常量 简单描述
1xx - 信息状态码。 - 不常见,暂不考虑
100 Continue 服务器准备接受请求主体,客户端发送请求主体;这容许客户端在请求发送大量数据以前询问服务器是否接受请求。 - 不常见,暂不考虑
101 Switching Protocols 服务器接受客户端在Upgrade首部字段中要求改变应用的协议请求,如从HTTP转换为WebSockets。 - 不常见,暂不考虑
2xx - 表示请求成功。 - -
200 OK 最多见的响应码,表明请求成功。若是请求方法是GET或者POST,所请求的数据与正常的首部都包含在响应体中。若是请求方法是HEAD,则只包含首部信息。 HTTP_OK 处理请求成功
201 Created 服务器已经在响应体中指定的URL建立了对应的资源。客户端如今应当尝试加载该URL。这个响应码只在响应POST请求时发送。 HTTP_CREATED 建立成功
202 Accepted 表示请求已经被处理,可是处理还没有结束,因此不会返回任何响应数据。 HTTP_ACCEPTED 接受请求
203 Non-Authoritative Information 由缓存代理或者其余本地源返回资源的表示,不能保证是最新的。 HTTP_NOT_AUTHORITATIVE 无权威的返回结果
204 No Content 服务器已经成功处理了该请求,可是没有信息发回给客户端。通常是因为服务器上的表单处理逻辑的问题,只接收数据不返回数据。 HTTP_NO_CONTENT 无返回内容
205 Reset Content 服务器已经成功处理了该请求,可是没有信息发回给客户端。客户端应该清除发送请求的表单信息。 HTTP_RESET 重置内容
206 Partial Content 服务器返回客户端请求的资源的部份内容,而不是整个文档。 HTTP_PARTIAL 部份内容
3xx - 重定向。 - -
300 Multiple Choices 服务器为所请求的文档提供一组不一样的表示。 HTTP_MULT_CHOICE 多重选择
301 Moved Permanently 资源已经移动到一个新的URL。客户端应当自动加载这个URL的资源。 HTTP_MOVE_PERM 永久移动
302 Moved Temporarity 资源暂时移动到一个新的URL,但其位置在不久的未来还会再次改变。 HTTP_MOVE_TEMP 临时移动
4xx - 客户端错误 - -
400 Bad Request 客户端向服务器发出的请求使用了不正确的语法。 HTTP_BAD_REQUEST 错误请求
401 Unauthorized 访问这个URL须要身份验证,通常是用户名和口令。 HTTP_UNAUTHORIZED 未受权
403 Forbidden 服务器理解请求,可是有意拒绝进行处理。 HTTP_FORBIDDEN 禁止访问
404 Not Found 最多见的错误响应,指示服务器找不到所请求的资源。 HTTP_NOT_FOUND 未找到资源
405 Method Not Allowed 请求方法不支持用于请求指定的资源。 HTTP_BAD_METHOD 方法禁用
406 Not Acceptable 所请求的资源不能以客户端但愿的格式提供,客户端指望的格式由请求HTTP首部Accept字段指定。 HTTP_NOT_ACCEPTABLE 不接受
5xx - 服务端错误 - -
500 Internale Server Error 服务器内部异常。 HTTP_SERVER_ERROR 服务器异常
501 Not Implemented 服务器不具有完成请求的功能。 HTTP_NOT_IMPLEMENTED 还没有实现
502 Bad Gateway 服务器做为网关或代理,从上游服务器收到无效响应。 HTTP_BAD_GATEWAY 错误网关
503 Service Unavailable 服务器暂时没法处理请求,多是超负荷或者维护等缘由。 HTTP_UNAVAILABLE 服务不可用

简单归纳以下:缓存

  • 响应码100-199表示一个提供信息的响应。
  • 响应码200-299表示请求成功。
  • 响应码300-399表示重定向。
  • 响应码400-499表示一个客户端引起的错误。
  • 响应码500-599表示一个服务器引起的错误。

常见的HTTP首部

下面简单列举一些比较经常使用的首部以及它们的做用。

User-Agent

User-Agent通常做为请求首部,用于告知服务器当前客户端使用的是什么浏览器,翻译过来就是用户代理,做用是容许服务器响应请求时候针对客户端用户代理的类型优化返回的数据或者文件。例如使用Chrome发送请求时,User-Agent以下:

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36

Host

Host通常做为请求首部,用于指定接收该请求的服务器的主机名和端口号。例如:

Host: www.importnew.com

Accept

Accept通常做为请求首部,它的做用是告知服务器它可使用或者想要什么已经不能使用或者不想要什么。下面是几个Accept首部以及它们的做用:

首部 做用
Accept 告知服务器客户端能够接收和处理哪些媒体类型
Accept-Charset 告知服务器客户端能够接收和处理哪些字符集
Accept-Encoding 告知服务器客户端能够接收和处理哪些编码方式
Accept-Language 告知服务器客户端能够接收和处理哪些语言

Accept首部用于指定接收媒体类类型的时候,须要指定类型和子类型,这是由于媒体类型(MIME)原本就是按二级分类的,例如JPEG图像的媒体类型是image/jpeg,类型是image,子类型是jpeg。MIME已经定义了八种顶级的类型:

  • text/*表示人可读的文字。
  • image/*表示图片。
  • model/*表示3D模型,如VRML文件。
  • audio/*表示音频。
  • video/*表示多媒体图片、视频,也多是音频。
  • application/*表示二进制数据。
  • message/*表示协议特定的信封,如Email消息和HTTP响应。
  • muitipart/*表示多个文档和资源的容器。

举个例子,若是客户端只接收JSON数据:

Accept: application/json

Referer

Referer通常做为请求首部,它提供了包含当前请求的URL的文档的URL,也就是当前请求的上一个来源的文档,通常用做防盗链。例如www.baidu.com/search?name=doge,服务器在处理此请求的时候,须要判断Referer是否为www.baidu.comwww.baidu.com/search的上一个文档来源必须是www.baidu.com,不然服务器应该拒绝该请求。

Cookie通常做为请求首部,客户端经过它向服务器传送一个或者多个令牌,原则上Cookie并非安全的首部,Cookie的内容也会缓存在客户端。通常在Servlet应用中,Cookie是识别当前用户,实现持久会话的最佳方式。从过时时间分类来看,Cookie分为会话Cookie和持久Cookie,会话Cookie的过时时间比较短,持久Cookie的过时时间比较长或者不会过时,Cookie的过时策略等控制应该由服务端控制。因为Cookie是直接暴露在客户端,通常不能使用Cookie存放敏感的数据,须要存放敏感数据能够考虑使用数据加密处理。

Cookie: uid=10086; domain="localhost"

Set-Cookie通常做为响应首部,和Cookie对应,表示服务器设置成功的Cookie。

Cache-Control

Cache-Control通常做为请求首部,告知服务器对当前的请求的响应结果进行缓存相关操做。Cache-Control支持的值比较多,这里不展开细节,常见的如no-cache表示在没有成功经过源站校验的状况下不得使用缓存,如max-age表示响应结果须要缓存到指定的最大时间。

Content-Type

Content-Type是通用首部,能够做为请求首部或者响应首部,它的做用是告知服务器或者客户端当前请求或者响应结果的内容(媒体)类型。

Content-Length

Content-Length是通用首部,能够做为请求首部或者响应首部,它的做用是告知服务器或者客户端当前请求或者响应数据体的长度。

Content-Encoding

Content-Encoding通常做为响应首部,与Accept-Encoding对应,用于服务器告知客户端当前响应结果的内容编码。

Content-Language

Content-Language通常做为响应首部,与Accept-Language对应,用于服务器告知客户端当前响应结果的内容语言。

Connection

Connection通常做为请求首部,表示是否须要持久链接。在HTTP1.1中,若是指定为Keep-Alive,能够提供持久链接,提升Socket的复用率从而下降屡次链接的性能消耗。下面有一个小节专门介绍Keep-Alive。

Orgin

Origin通常做为请求首部,指明当前的请求是一个针对跨域资源共享的请求(该请求要求服务器在响应中加入一个Access-Control-Allow-Origin的消息头,表示访问控制所容许的来源)。

Origin: http://www.baidu.com

Access-Control-Allow-Origin

Access-Control-Allow-Origin通常做为响应首部,和Origin对应,表示服务器容许的该跨域资源共享的请求来源。

Access-Control-Allow-Origin: http://www.baidu.com

Server

Server通常做为响应首部,用于告知客户端服务器的相关信息。

HTTP请求体

若是采用GET请求方法,只须要向远处服务器提供URL,URL中的路径和查询字符串就能够匹配到须要查询的资源。可是URL中没法提供详细的客户端信息。另外,像POST和PUT这些请求方法所携带的数据体有可能比较大,没法放在URL的查询字符串。所以HTTP须要请求体。HTTP请求体包括下面四个部分:

  • 一、一个起始请求行,包括HTTP方法、路径、查询字符串以及HTTP版本。
  • 二、HTTP请求的首部。
  • 三、一个空行(两个连续的回车或者换行对)。
  • 四、请求数据体。

文字描述可能比较抽象,用图表示以下:

http-1

PS:space表明空格,\r\n表明换行。

举个例子:

GET /wp-admin/admin-ajax.php?postviews_id=23996&action=postviews&_=1538708851063 HTTP/1.1
Host: www.importnew.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36
Referer: http://www.importnew.com/23996.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

postviews_id=23996&action=postviews&_=1538708851063

HTTP响应体

响应体和请求体的格式相似,主要是返回服务器的响应数据到客户端,包括服务器的一些信息和响应数据体。HTTP响应体主要包括下面的四个部分:

  • 一、一个起始响应行,包括HTTP版本、状态码、状态码描述。
  • 二、HTTP响应的首部。
  • 三、一个空行(两个连续的回车或者换行对)。
  • 四、响应数据体。

文字描述可能比较抽象,用图表示以下:

http-2

PS:space表明空格,\r\n表明换行。

举个例子:

HTTP/1.1 200 OK
Server: nginx
Date: Fri, 05 Oct 2018 03:07:37 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=2
Vary: Accept-Encoding
X-Powered-By: PHP/5.3.3
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Encoding: gzip

2995

Keep-Alive

在使用HTTP1.0的时候会为每一个请求打开一个新的TCP链接,实际上,这致使了一个典型Web会话中打开和关闭全部链接所花费的事件远远大于实际传输数据所消耗的时间,特别是响应结果包含不少小文档的会话。对于使用SSL或者TLS加密的HTTPS链接,这个问题更加严重,由于创建一个安全的Socket的握手过程远比创建常规的Socket须要更多的工做。

在HTTP1.1和后面的版本中,服务器没必要在返送响应以后就关闭链接。已经创建的链接能够保持打开,在同一个Socket上等待来自客户端的新请求。简单来讲,就是能够在一个TCP链接上连续发送多个请求和连续进行多个请求的响应。

客户端能够在HTTP请求首部中添加一个Connection请求头,指定值为Keep-Alive,这样就能实现Socket的重用:

Connection: Keep-Alive

HTTP1.1或者以后的版本,Keep-Alive是默认开启的,不须要显式指定,若是须要关闭能够设置为close:

Connection: close

一旦开启了Keep-Alive,服务器在关闭一个Socket链接以前,若是有新的客户端再次链接到服务器,那么就是重用Socket。在JDK中能够经过系统属性来控制若是使用HTTP的Keep-Alive:

  • http.keepAlive:默认值为true,默认开启HTTP的Keep-Alive。
  • http.maxConnections:同时保持打开的Socket数量的最大值,默认值为5。
  • http.keepAlive.remainingData:默认值为false,若是设置为true,则JDK在丢弃链接以后会完成剩余数据的清理。
  • sun.net.http.errorstream.enableBuffering:默认值为false,若是设置为true,则尝试缓存400和500状态码的相对小的错误流,从而能释放链接以备后续使用。
  • sun.net.http.errorstream.bufferSize:为缓存错误流的缓冲区的字节大小,默认值为4096字节,只有上一项为true的时候才有意义。
  • sun.net.http.errorstream.timeout:默认值为300ms,读取错误流超时的毫秒数。

Cookie和Cookie管理

不少网站使用一些小文本串在链接之间存储持久的客户端状态,这些小文本串称为Cookie(中文翻译为:小甜点)。Cookie在请求和响应的首部从服务器传到客户端,再从客户端传回服务器,服务器使用Cookie来指示sessionID、购物车内容、登陆凭据等。
除了简单的name=value对,Cookie能够有多个属性来控制它们的做用域,包括过时日期、路径、域、端口、版本和安全选项。

JDK中java.net.CookieStore类提供了对Cookie的增删查操做,它的默认实现是java.net.InMemoryCookieStore,若是实现CookieStore,JDK中的Cookie默认是存放在内存中的。另外,java.net.CookieManager内部持有CookiePolicy和CookieStore,定义了一系列管理Cookie的方法,通常经过CookieManager操做Cookie,固然也能够经过实现CookieStore,覆盖默认的CookieManager来实现Cookie的自定义管理。

小结

(本文完 c-2-d e-20181005)

相关文章
相关标签/搜索