1.介绍
HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写,用户从web服务器传输超文本到客户端浏览器的应用层传送协议。由请求和响应构成,是一个无状态协议。
2.在TCP/IP协议栈中的位置
HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议之上,这时候就变成了HTTPS。如图:
默认HTTP的端口号为80,HTTPS的端口号为443。
3.HTTP请求
Http请求由四个部分组成,分别是:请求行(request line)、请求头部(header)、空行(CRLF)、请求数据。
3.1 请求行
格式:[Method] [Request-url] [Http-version] CRLF
其中Method表示请求方法,Request-url表示请求的url(可以是相对路径),Http-version表示请求的HTTP协议版本,CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符。
eg:
GET /hello.txt HTTP/1.1
3.2请求头部
HTTP客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是GET或POST)。如有必要,客户程序还可以选择发送其它的请求头。大多数请求头并不是必须的,但Content-Length除外。对于POST请求来说Content-Length必须出现。
常见请求字段含义:
Accept:浏览器可以接受的MIME类型(MIME是描述消息内容类型的因特网标准,MIME消息能包含文本/图像/音频/视频以及其他应用程序专用的数据)
Accept-Charset:浏览器可接受的字符集
Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经过gzip编码的HTML页面
Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到
Authorization:授权信息,通常出现在对服务器发送的www-Authenticate头的应答中
Content-Length:表示请求消息正文的长度
Host:客户机想访问的主机名,HTTP/1.1请求必须包含主机头域,负责返回400错误
Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的(防盗链)。包含一个URL,用户从该URL代表的页面出发访问当前请求的页面
Cookie:客户机通过这个头可以向服务器带数据
Connection:处理完这次请求后是否断开连接。如果这里的值为"Keep-Alive",表示持久连接。
3.3 CRLF的作用是通过一个空行告诉服务器请求头部到此为止。
3.4请求数据
方法字段是GET时,此项为空。
方法字段是POST时,则通常来说此处放置的就是他要提交的数据。
4.HTTP响应
HTTP响应报文由四部分组成:状态行、消息头部、响应正文
4.1状态行
格式:[Http-version] [status code] [status describe]
比如:
HTTP/1.1 200 OK
4.2消息头部
用于描述服务器的基本信息,以及数据的描述。
常见消息头部字段含义:
Allow:服务器支持哪些请求方法(如,post/get)
Content-Type:表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html
Content-Encoding:文档编码的方法
Content-Length:文档长度。只有当浏览器使用Keep-Alive持久连接时才需要这个数据
Date:当前的GMT时间
Location:这个头配合302状态码使用,用于重定向接收者到一个新的URI地址。
Refresh:告诉浏览器隔多久刷新一次
Server:服务器的类型
Set-Cookie:设置和页面关联的Cookie。Servlet不应使用response.setHeader("Set-Cookie",...),而是使用HttpServletResponse提供的专用方法addCookie。
Transfer-Encoding:告诉浏览器数据的传送格式
注:设置应答头最常用的方法是HttpServletResponse的setHeader,该方法有两个参数,分别表示应答头的名字和值。
和设置状态代码相似,设置应答头应该在发送任何文档内容之前进行。
setDateHeader方法和setIntHeadr方法专门用来设置包含日期和整数值的应答头,前者避免了把Java时间转换为GMT时间字符串的麻烦,后者则避免了把整数转换为字符串的麻烦。
HttpServletResponse还提供了许多设置
setContentType:设置Content-Type头。大多数Servlet都要用到这个方法。
setContentLength:设置Content-Length头。对于支持持久HTTP连接的浏览器来说,这个函数是很有用的。
addCookie:设置一个Cookie(Servlet API中没有setCookie方法,因为应答往往包含多个Set-Cookie头)。
4.3空行告诉浏览器响应头部到此为止。
4.4响应正文
响应正文,如果是纯数据就返回纯数据,如果请求的是HTML页面,那么返回HTML代码,如果是JS就是JS代码。
5.HTTP消息头
头由一系列行组成,每行都包含名称,然后依次是冒号、空格、值。字段可按任何顺序排列。某些头字段既能用于请求头也能用于响应头(实体头字段),而另一些头字段只能用于其中之一。
许多请求头字段都允许客户端在值部分指定多个可接受的选项,有时甚至可以对这些选项的首选项进行排名。多个项以逗号分隔。例如,客户端可以发送包含“Content-Encoding: gzip, compress,”的请求头,表示可以接受各种压缩类型。如果服务器的响应正文使用 gzip 编码,其响应头中将包含“Content-Encoding: gzip”。
6.GET和POST
6.1参数位置
Get请求的数据会附在URL之后(就是Http请求行的url),会直接展现在地址栏中,以?分隔URL和数据,参数之间以&相连。
如:login.action?name=xx&password=yy&verify=%E4%BD%A0%E5%A5%BD
数据中,字母/数字不变,空格转换为+,中文/其他字符用BASE64加密。
POST方法会把数据放到“请求数据”字段中以&分隔。
6.2POST方法
Post方式发送的命令要严格、复杂,需要提供提交的数据类型及长度。
数据类型有两种,一种是普通的文本数据(ASCII数据),类型为"application/x-www-form-urlencoded"。
例如:
POST /s HTTP/1.1
Content-Type:application/x-www-form-urlencoded
Content-Length:7
wd=java
另一种是文件数据(二进制数据),类型为"multipart/form-data"。
Content-Type: multipart/form-data; boundary=${bound},其中${bound}是一个分隔符
例如:
--${bound}
Content-Disposition: form-data; name="Filename"
HTTP.pdf
--${bound}
Content-Disposition: form-data; name="file000"; filename="HTTP协议详解.pdf"
Content-Type: application/octet-stream
%PDF-1.5
file content
%%EOF
--${bound}
Content-Disposition: form-data; name="Upload"
Submit Query
--${bound}--
其中${bound}是之前头信息中的分隔符,如果头信息中规定是123,那这里也要是123;可以很容易看到,这个请求提是多个相同部分组成的:每一部分都是以--加分隔符开始的,然后是该部分内容的描述信息,然后一个回车,然后是描述信息的具体内容;如果传送的内容是一个文件的话,那么还会包含文件名信息以及文件内容类型。上面第二部分是一个文件体的结构,最后以--分隔符--结尾,表示请求体结束。要发送一个multipart/form-data的请求,其实任何支持post请求的工具或语言都可以支持,只是自己要稍微包装一下便可。
7.请求响应实例
下面实例是一点典型的使用GET来传递数据的实例:
客户端请求:
GET /hello.txt HTTP/1.1 User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 Host: www.example.com Accept-Language: en, mi
服务端响应:
HTTP/1.1 200 OK Date: Mon, 27 Jul 2009 12:28:53 GMT Server: Apache Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT ETag: "34aa387-d-1568eb00" Accept-Ranges: bytes Content-Length: 51 Vary: Accept-Encoding Content-Type: text/plain