HTTP协议简介详解 HTTP协议发展 原理 请求方法 响应状态码 请求头 请求首部 java模拟浏览器客户端服务端
协议简介
协议,自然语言里面就是契约,也是双方或者多方经过协商达成的一致意见;
契约也即类似于合同,自然有甲方123...,乙方123...,哪些能做,哪些不能做;
通信协议,也即是双方通过网络通信必须遵从的一组约定;
计算机网络的本质在于传递数据,协议自然是针对于数据的结构格式以及传送规则的约定;
之前介绍过计算机网络的发展,其中TCP/IP协议栈共分为四层,两个程序端点数据的传输是U字形的
应用层
传输层
网络层
网络接口层
HTTP是工作在应用层的协议,所谓的工作在哪层,只不过是对底层的封装程度而已;
HTTP协议是什么
HTTP协议是Tim(计算机发展系列提到过)发明的,也正是他完成了万维网三大基础技术的设计:命名方案(URI),通信协议(HTTP)和用来表示信息的标记语言(HTML);
回过神来仔细想想web的发展过程,web是B/S结构的,浏览器(B)通过网络向服务器(S)请求数据,
有了TCP/IP协议以及Socket编程,你可以很容易的完成服务器与请求方的数据沟通;
但是信息的传递的重点在于信息本身,而不是这一次的数据交换,必须要能够相互理解;
因为单纯的数据交流并没有任何意义,必须有对话的基础,那就是"语言";
就好像你(请求方)在说普通话,水果店老板(服务器)在讲英语,你们从早上交流到晚上可能并没有有效的传递任何信息;
所以HTTP协议就是这样一种用于浏览器客户端与服务器交流的一种"语言";
他规定了对话的语法以及格式,有了HTTP协议,客户端和服务器端就可以相互理解对方,才能达到信息交换的目的;
既然HTTP是为了WEB创造的,自然是请求获取的一个过程,而且当时就是HTML
所以最初他就是这么简单,获取一个名为XXX的HTML文件
GET /index.html
1991年Tim写了一篇关于HTTP的协议的文章,被看做是HTTP/0.9
地址:https://www.w3.org/Protocols/HTTP/AsImplemented.html
HTTP-Hypertext Transfer protocol ,超文本传输协议,他的名字完整的对自己进行了释义:传输超文本HTML文件的协议;
HTTP协议的发展
最初的版本,看起来可能比较简陋,他只能单独的请求数据,连是不是请求出错了都无法感知,显然,这不可能持续满足需求;
1996年 HTTP/1.0 版本发布
1.0是相对于0.9的大阔步发展,增加了很多内容,详见RFC1945 https://tools.ietf.org/html/rfc1945
不再限制内容的格式只能是HTML,任何格式都可以;
除了GET还引入了POST 和 HEAD 丰富了浏览器客户端和服务器的交互
HTTP请求和相应的格式信息也更加丰富,还增加了状态码等等内容
1997年1月,HTTP/1.1 版本发布,只比 1.0 版本晚了半年,1.1是1.0的升级优化版,重点在于完善优化
这也是目前一直在用的一个版本
HTTP协议的格式
HTTP默认的端口号为80,HTTPS的端口号为443,HTTP协议包括请求和响应
其中CRLF是回车换行
此图片来自于<计算机网络> ,首部也就是前面图中的头部 一个意思
请求和响应都包括:行/头部/主体
请求行包括:方法/URL/版本号
响应行包括:版本号/状态码/描述
请求头和响应头都是KEY:VALUE的键值对形式,个数为n
头部可以分成三个部分:请求/响应头字段、通用头字段、实体头字段。
其中通用头字段和实体头字段部分内容也在响应部分有相同的定义。
请求体通常不用,响应体也不一定用;
HTTP请求方法
HTTP请求方法有下面几种,常用的有GET、POST请求.
GET | 请求指定的页面信息,并返回实体主体。 |
POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 |
HEAD | 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头 |
PUT | 从客户端向服务器传送的数据取代指定的文档的内容。 |
DELETE | 请求服务器删除指定的资源。 |
CONNECT | HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 |
OPTIONS | 允许客户端查看服务器的性能。 |
TRACE | 回显服务器收到的请求,主要用于测试或诊断,还回测试的请求报文 |
HTTP状态码
三位数字表示,第一位表示类型
1XX 消息,服务器收到请求,需要请求者继续执行操作
2XX 成功,操作被成功接收并处理
3XX 重定向,需要进一步的操作以完成请求
4XX 客户端错误,请求包含语法错误或无法完成请求
5XX 服务器错误,服务器在处理请求的过程中发生了错误
100 | Continue | 继续。客户端应继续其请求 |
101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
200 | OK | 请求成功。一般用于GET与POST请求 |
201 | Created | 已创建。成功请求并创建了新的资源 |
202 | Accepted | 已接受。已经接受请求,但未处理完成 |
203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 |
300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 |
306 | Unused | 已经被废弃的HTTP状态码 |
307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
402 | Payment Required | 保留,将来使用 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 |
405 | Method Not Allowed | 客户端请求中的方法被禁止 |
406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 |
407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 |
409 | Conflict | 服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突 |
410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 | Precondition Failed | 客户端请求信息的先决条件错误 |
413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 |
415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 |
416 | Requested range not satisfiable | 客户端请求的范围无效 |
417 | Expectation Failed | 服务器无法满足Expect的请求头信息 |
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 |
502 | Bad Gateway | 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求 |
503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
HTTP头部-通用头字段
请求和响应都会用到的头部字段
- Cache-Control 指定请求和响应遵循的缓存机制
- Connection 控制不在转发给代理的首部也就是有些首部信息通过他控制删除后转发,另外就是是否持久连接1.1默认持久
- Date 报文创建的日期和时间 http1.1使用RFC1123中规定的格式
- Pragma 遗留字段 形式唯一 Pragma:no-cache,虽是通用,但仅用于请求,要求所有中间服务器不返回缓存的资源
- Trailer 事先说明报文主体之后记录了哪些头字段
- Transfer-Encoding 传输报文主体时采用的编码方式
- Upgrade 检测HTTP协议以及其他协议是否可以使用更高版本通信,参数还可以指定一个完全不同的通信协议
- Via 追踪客户端和服务器之间的请求和响应报文的传输路径
- Warning 告知用户一些与缓存相关的问题的警告
HTTP头部-请求头字段
从客户端向服务器端发送请求时使用到的头字段,补充了请求的附加内容,客户端信息,响应内容优先级等信息
1.Accept
告知服务器,能够处理的媒体类型以及媒体类型的相对优先级 可使用type/subtype的形式,一次指定多种类型
比如 text/html,text/plain,text/css………
2.Accept-Charset
告知服务器,能够处理的字符集以及字符集的相对优先级
也可以一次指定多个
3.Accept-Encoding
告知服务器,支持的内容编码以及内容编码的相对优先级,可以一次性指定多种内容编码 gzip,compress,deflate,identity
4.Accept-Language
告知服务器,能够处理的自然语言集,比如中文 英文 ,以及自然语言的相对优先级,可以一次性指定多种自然语言集
5.Authorization
告知服务器,认证信息
6.Expect
告知服务器,期望出现的某种特定行为
7.From
告知服务器,电子邮件地址
8.Host
告知服务器,请求资源的主机名以及端口号,Host是请求头字段里面,HTTP1.1唯一一个要求必须有的字段
形如If-Xxx的请求头字段,都是条件字段,服务器会判断这个条件,只有条件为真的时候才会执行请求
9.If-Match
告知服务器,匹配资源所用的实体标记ETag的值 如果使用*号,服务器将忽略不在比较
10.If-Modified-Since
告知服务器,指定的日期后资源发生了更新,服务器会接受响应 ,参数为日期时间
11.If-None-Match
与If-Match原理一样,取值相反
12.If-Range
属于附带条件之一 字段值若是跟ETag或者更新日期时间匹配一致,那么作为范围请求处理,否则返回全部资源
13.If-Unmodified-Since
原理同If-Modified 取值相反
14.Max-Forwards
通过TRACE或者OPTIONS,发送包含此字段的请求,以十进制形式指定可经过的服务器最大数目
15.Proxy-Authorization
认证相关
16.Range
对于只获取部分资源的范围请求,告知服务器资源的指定范围,服务器接收Range处理后还会返回206 无法处理则会忽视,返回200以及全部资源
17.Referer
告知服务器请求的原始资源的URI
18.TE
告知服务器,客户端能够处理的响应的传输编码方式以及相对优先级,注意是传输,传输中编码
19.User-Agent
创建请求的浏览器和用户代理名称等信息传达给服务器
HTTP头部-响应头字段
从服务器端返回响应时用到的头部字段,补充了响应的附加内容
1.Accept-Ranges
告知客户端,服务器是否能够处理范围请求,如果不能值为none,Accept-Ranges:none;否则是bytes
2.Age
告知客户端,源服务器在多久前创建了响应,字段值单位为s,如果是缓存服务器值为缓存后的响应再次发起认证到认证完成的时间值,代理创建响应必须加上Age
3.Etag
告知客户端实体标识,可以将资源以字符串形式唯一标识的方式,服务器会给每个资源创建ETag值,资源更新,Etag也需要更新
4.Location
将响应接收方引导至某个请求URI位置不同的资源,基本上字段会配合3XX,几乎所有的浏览器接收到Location响应都会强制尝试对已经提示的信息进行重定向
5.Proxy-authenticate
代理服务器需要的认证信息发送给客户端
6.Retry-After
告知客户端,多久后重新请求,主要配合503或者3xx Redirect响应一起使用
7.Server
告知客户端,服务器上安装的HTTP服务器应用程序信息
8.Vary
源服务器向代理服务器传达对缓存进行控制的信息,
9.WWW-Authenticate
用于HTTP访问认证
HTTP头部-实体头字段
针对请求和响应报文的实体部分使用的头字段,用于补充内容的更新时间等与实体相关的信息
1.Allow
通知客户端能够支持Request-URI指定资源的所有HTTP方法,收到不支持的方法请求时,返回405 Method Not Allowed,还会把支持的方法写入首部字段Allow返回
2.Content-Encoding
会告知客户端 服务器 对实体的主体部分选用的内容编码方式,指在不丢失信息的前提下进行压缩
3.Content-Language
告知客户端,实体主体使用的自然语言比如中文 英文
4.Content-Length
实体主体部分的大小,单位字节
5.Content-Location
给出与报文主体部分相对应的URI,和Location不同,本字段表示的是报文主体返回资源对应的URI
6.Content-MD5
MD5生成的值,目的在于检查报文主体传输过程中是否保持完整,客户端通过对报文主体执行相同的MD5算法然后比对,确认传输到达
7.Content-Range
针对范围请求,返回响应时使用的首部字段,告知客户端 作为响应返回的实体的 哪个部分符合范围请求. 字节为单位
8.Content-Type
实体主体内对象的媒体类型,用type/subType设置
9.Expires
资源失效的日期告诉客户端,接收到Expires的响应后会以缓存来应答,指定的时间值之前,响应的副本会一直保存,超过指定时间,缓存服务器会转向源服务器,优先级比Cache-Control max-age低
为Cookies服务的头部字段
Set-Cookie 开始状态管理所使用的Cookie信息 响应头字段
Cookie 服务器接收到的Cookie信息 请求头字段
Set-Cookie 字段属性
Name=value 键值对的形式 必须
expires=DATE 有效期,不指定默认为浏览器关闭
path=PATH 服务器上的文件目录作为Cookie的适用对象,不指定默认为当前目录
domain=域名 作为Cookies适用对象的域名,不指定默认为创建Cookie的服务器域名
Secure 仅仅HTTPS下才发送Cookie
HttpOnly 限制,js不能使用Cookie
模拟浏览器和服务器原理
说了那么多HTTP协议,其实终究也还只是个信息传递交互的一个格式.
所以说,你只要发送指定格式的数据到服务器,就能像浏览器一样请求数据
只要能够接受请求返回HTTP协议指定的格式的响应,浏览器就能解析数据
网络编程离不开Socket,Socket也是一个IO流,只不过通过Socket实现的是客户端与服务端的IO读写
服务器的I是客户端的O
客户端的I是服务器的O
下面的例子非常的简单,当然也不怎么完善,但是你可以清晰地看到,协议,的作用,
//客户端浏览器 import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class Client { public static void main(String[] args) throws UnknownHostException, IOException { //建立客户端Socket Socket s = new Socket("www.baidu.com",80); //获取输出流 客户端的输出流也即是服务端的输入流 //也就是发送数据到服务器 PrintWriter out = new PrintWriter(s.getOutputStream(),true); out.println("GET /error.html HTTP/1.1"); out.println("Accept: */*"); out.println("Host: www.baidu.com"); out.println("Connection: close"); out.println(); out.println(); //接收服务器的响应信息 //客户端的输入流就是服务器输出流 InputStream in = s.getInputStream(); //缓冲区 1024 byte[] buf = new byte[1024]; int len = in.read(buf); //打印信息 String str =new String(buf,0,len); System.out.println(str); s.close(); } }
//服务端 import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { //服务端socket ServerSocket ss = new ServerSocket(8080); //等待请求 Socket s = ss.accept(); System.out.println(s.getInetAddress().getHostAddress()+".....connected"); //获取输入流打印客户端请求信息 InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); String text = new String(buf,0,len); System.out.println(text); //发送数据到客户端 PrintWriter out = new PrintWriter(s.getOutputStream(),true); out.println("<font color='green' size='10'>welcome</font>"); s.close(); ss.close(); } }
如果有的浏览器打不开,请用IE浏览器,毕竟就随便输出了一条头部信息等都没有好好搞
HTTP协议总结:
所谓协议就是有固定格式结构,有约定语义;
大家都基于这种语义进行交流沟通;HTTP协议也是如此,他不关注具体的数据,只关心数据的格式以及语义;
所以只要你发送符合HTTP协议的指定格式的请求数据,你就能得到服务器的响应;
只要你返回符合HTTP协议的指定格式的响应数据,你就能正确发送信息到客户端;
服务器端和浏览器(客户端)通过HTTP这一协议进行数据交互,实现了服务器端与浏览器端的解耦
正是解耦,使得浏览器和服务器技术可以相互独立发展;