您的位置:首页 > 理论基础 > 计算机网络

自己实现Http服务器:一、Http协议解析

2015-01-05 10:47 267 查看
之前总结过一篇TCP/IP协议的文章,而Http就是建立在TCP的基础之上的。TCP、UDP属于传输层协议,而Http是属于应用层的协议。

Http是超文本传输协议的缩写。协议详细内容参考RFC2616。由于面向文本的,所以使用ASCII编码。

Http特点

1. 客户/服务器模式,支持基本认证和安全认证(Https)

2. 简单快速

3. 灵活:允许传输任意类型数据,通过Content-Type标记

4. Http1.0使用短连接方式,Http1.1支持长连接方式

5. 无状态:对事务处理没有记忆能力

Http报文可以分为请求报文和响应报文两种。下面先给出各报文的例子方便后面的理解

Get请求消息例子:

==========

GET /doaction?p=123&k=3343 HTTP/1.1

Host: localhost:12345

Connection: keep-alive

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36

Accept-Encoding: gzip, deflate, sdch

Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4

Cookie: name=jackey;

===========

Post请求消息例子:

===========

POST /post HTTP/1.1

Host: localhost:12345

Connection: keep-alive

Content-Length: 11

Cache-Control: max-age=0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Origin: http://localhost:12345

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36

Content-Type: application/x-www-form-urlencoded

Referer: http://localhost:12345/doaction?p=123&k=3343

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4

name=jackey

===========

响应消息例子:

===========

HTTP/1.1 200 OK

Connection:keep-alive

Content-Type: text/html;charset=UTF-8

Content-Length:51

Date:2014-12-31 16:02:17

Server:HttpServer

Set-Cookie: name=jackey; Expires=Tue, 03-Feb-2015 08:29:31 GMT; Path=/; Secure

<html><head>title</head><body>content</body></html>

===========

Http采用请求响应模型,浏览器向服务器发送请求,服务器响应消息返回给浏览器。所以http消息分为两种:请求消息和响应消息。(注意消息中的换行都是CRLF,不允许出现单独的CR或LF字符)

这两种消息的结构差不多:

1.一个起始行

2.一个或多个头域 

3.一个头域结束标志的空行(CRLF)

4.可选的消息体

请求消息结构:

1.请求行

2.请求头

3.头域结束标志的空行

4.请求正文

响应消息结构:

1. 状态行

2. 响应头

3. 头域结束标志的空行

4. 响应正文

起始行

请求起始行格式:

【请求方法】【空格】【请求URI】【空格】【协议版本】

URI通常只要给出服务器根目录的相对目录即可,所以总是以“/”开头。

响应起始行格式:

【协议版本】【空格】【状态码】【空格】【服务器信息】

支持以下这几种方法:

GET、HEAD、POST、OPTIONS、PUT、Delete、TRACE、CONNECT

其中最常用的是GET、POST和HEAD,一般自己做用于应用的http服务器的时候只需要考虑支持这三种方法即可适用于大多数场景。

HEAD方法和GET方法几乎一样,它们的头部是相同的,服务端可以对HEAD方法只返回响应的头部。这一般是爬虫程序会用到这个方法,来测试超链接的有效性,以及最近更新情况。

响应状态码

1XX:信息类,表示接收到请求并且继续处理

2XX:成功类,表示被成功接收、理解和接受

3XX:重定向,为了完成指定动作,必须接受进一步处理

4XX:客户端错误。请求的语法错误或不能正确执行

5XX:服务端错误。服务器不能正确指定一个正确的请求

常用状态吗

200 OK //请求成功

302 Found //请求的资源被临时替代,新的URL在Location头域中

304 Not Modified //告诉客户端该被缓存的文档未修改,可以直接使用缓存

400 Bad Request //请求有语法错误,不能被服务器所理解

401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 

403 Forbidden //服务器收到请求,但是拒绝提供服务

404 Not Found //请求资源不存在,eg:输入了错误的URL

500 Internal Server Error //服务器发生不可预期的错误,不能完成请求

502 Bad Gateway //服务器作为网关或代理访问下一个服务器失败

503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

头域

头域格式:

【域名】【冒号:】【域值】

域值前可以加任意空格不影响域值。

头域可以被扩展为多行,需要在每行开始处使用至少一个空格或制表符。

规范中并没有对头域长度和数量进行限制,但出于性能和安全考虑,多数http服务器会进行一定的限制,如Apache2.3限制头部不能超过8190字节,头域数量不能超过100个。

请求头域

Accept:客户端(浏览器)可以接收的内容类型

Accept-Charset:浏览器可以处理的字符集,如utf-8

Accept-Encoding:浏览器可以处理的编码方式,如gzip,deflate

Accept-Language:浏览器可接收的语言,zh-CN

Authorization:认证保护的信息的base64编码

Cache-Control:缓存机制。

        public:所有内容都将被缓存
        private:内容只缓存到私有缓存
        no-cache:所有内容都不会被缓存
        no-store:所有内容都不会被缓存到缓存或Internet临时文件中
        must-revalidate/proxy-revalidate:如果缓存失败,请求必须重新验证
        max-age:缓存的内容将在XXX秒后失效,如果和Last-Modified一起使用优先级较高

Connection:告诉服务器使用的连接方式:keep-alive和close。http1.1和http1.0的长连接和短连接。

Cookie:格式:name=value;name=value

Content-Length:请求体的长度(单位字节),头域的结束标志空行之后开始算。

Content-MD5:base64编码的请求体的MD5校验和。

Content-Type:请求体内容的MIME类型,如application/x-www-form-urlencoded

Date:发送请求的GMT时间

From:发送请求的用户的email地址

Host:服务器的域名或IP地址,以及端口。

Referer:指当前请求的URL是在什么地址引用的。通常我们见到的图片防盗链就是用这个实现的

User-Agent:用户浏览器信息

Range:表示请求资源的从某个数值到某个数值间的数据。如Range: bytes=500-999 就是表示请求资源从500到999byte的数据。数据的分段下载和多线程下载就是利用这个实现的

Upgrade:请求服务器更新至另外一个协议

If-Match:通常在PUT方法的请求中,通过资源的tag与If-Match的tag匹配判断,是否更新

If-Modified-Since:询问服务器现在正在请求的资源在某个时间以来有没有被修改过,如果没有,服务器则返回304状态来告诉浏览器使用浏览器自己本地的缓存,如果有修改过,则返回200,并发送新的资源(当然如果资源不存在,则返回404。)

If-None-Match:和If-Modified-Since用意差不多,不过不是根据时间来确定,而是根据一个叫ETag的东西来确定

If-Range:告诉服务器如果这个资源没有更改过,就发送这个资源中在浏览器缺少了的某些部分给浏览器,如果该资源以及被修改过,则将整个资源重新发送一份给浏览器

If-Unmodified-Since:询问服务器现在正在请求的资源在某个时刻以来是否没有被修改过

Max-Forwards:限制请求信息在代理服务器或网关中向前传递的次数

Pragma:用来包含实现特定的指令,如Pragma:no-cache,同Cache-Control:no-cache

Proxy-Authorization:连接到某个代理时使用的身份认证信息,跟Authorization头差不多

Via:用来记录一个请求经过了哪些代理或网关才被送到目标服务器上

Warning:记录一些警告信息

通用但非标准的HTTP头(通常,非标准的头域都是用“X-”开头,例如"x-powered-by"):

X-Requested-With:主要用来识别ajax请求,如XMLHttpRequest

DNT:DO NOT TRACK的缩写,要求服务器程序不要跟踪记录用户信息。1开启,0关闭

X-Forwarded-For:记录一个请求从客户端出发到目标服务器过程中经历的代理,或者负载平衡设备的IP

X-Forwarded-Proto:记录一个请求最初从浏览器发出时候,是使用什么协议,如https,http

Front-End-Https:微软使用与其负载平衡的一个头域

X-ATT-DeviceId:

响应头域

Access-Control-Allow-Origin:表示该站点可以被哪些网站进行跨域资源共享(cross-origin resource sharing,CORS),如Access-Control-Allow-Origin:http://foo.example.com,Access-Control-Allow-Origin:*

Accept-Ranges:表明服务器支不支持资源范围请求,bytes表示支持,none则不支持

Age:一个资源存在于代理中缓存的时间。单位是秒

Allow:允许哪些HTTP方法进行请求,例如:Allow: GET, HEAD

Cache-Control:见上文

Connection:连接方式,keep-alive和close

Content-Encoding:服务器对响应数据的编码方式,如gzip

da42

Content-Language:响应数据的自然语言,如zh-CN

Content-Length:响应体数据的长度

Content-MD5:base64编码的响应体的MD5检验和

Content-Disposition:当客户端请求资源是一个可下载的资源时,对这个资源的描述。如文件名等,浏览器下载框的文件名就是从这获取的。

Content-Range:表示如果当前这个响应数据是整个资源的一部分时,是具体的哪一部分。例如:Content-Range:500-900

Content-Type:响应数据的MIME类型,例如:Content-Type: text/html; charset=utf-8

Date:响应消息发送的GMT格式日期

ETag:(Entity-Tag的缩写)资源的一个标识,类似于key-value pair(键值对)中的key。ETag通常用于校验一个资源实体有没有被修改过

Expires:告诉客户端该响应数据会在指定的时间过期,通常用于给客户端缓存作为参考

Last-Modified:客户端所请求的资源的最后修改时间

Link:描述当前被请求的资源和另外一个资源的关系

Location:用户通知客户端转跳(重定向)到另一个URL

P3P:表示本站点遵守P3P协议(标称本站点不会违法使用用户信息)并希望收集用户信息

Proxy-Authenticate:访问代理时需要使用的验证方式。例如:Proxy-Authenticate: Basic

Refresh:用于令客户端在指定N秒后转跳到另外一个URL。例如:Refresh:6,http://www.google.com.hk 6秒后转跳到google

Retry-After:用于因为某些原因(例如该资源暂时无效)通知客户端在指定时间后重新尝试请求,时间单位为秒。例如:Retry-After:60 一分钟后重新尝试请求该资源

Server:服务器的名称

Set-Cookie:对客户端设置cookie。例如:Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1

Strict-Transport-Security:用于指示客户端如何对HTTPS进行缓存(缓存多长时间)以及是否对子域生效

Trailer:当响应资源已chunked编码传输时,每个Chunked-Body尾部的额外数据

Transfer-Encoding:响应内容的传输编码方式,通常有 chunked, deflate, gzip等

Vary:用来指示缓存代理(例如squid)根据什么条件去缓存一个请求

Via:告诉客户端,该回应经历了那些代理

WWW-Authenticate:表示当前是用什么验证方式访问一个资源

通用的非标准HTTP头域:

X-XSS-Protection:IE8+中开启或关闭跨站脚本攻击

X-Content-Type-Options:只有一个值:nosniff,正是用于关闭自动嗅探功能

X-Powered-By:表面当前站点(或资源)是用什么技术开发

Http1.1和Http1.0的区别

Http1.1使用的是长链接,根据头部中的Connection值来判断是否继续保持TCP链接,当值是keep-alive时服务器保持连接,值是close时响应内容后就可以关闭连接了。而Http1.0则没有这种长链接的概念,每次请求响应后建立的链接就断开,这样浪费了很多网络资源用于重新建立连接。

当然,http服务器在实现的时候,也会有个超时时间,超过这个时间这个连接一直没有交互(读或写),也会关闭这个连接。

Http1.1在Http1.0基础上,在头部还增加了一些头域。如Host字段,可以根据这个知道客户端通过什么域名访问的,用这个可以在同一个IP端口下配置多个WEB站点,根据域名来分发到相应的server进程。还有上面提到的Connection字段等等。

Http1.1判断正文结束

由于http1.1.使用的是长连接的方式,所以浏览器需要知道响应的正文在什么位置该结束。有两种方式:

1. 通过头部中的Content-Length来获取正文的长度,这样就知道什么时候这个请求结束。这也是最常用的方式。

2. 没有Content-Length时,可以通过chunk编码,来一块一块的发送正文。在请求头部中添加Transfer-Encoding: chunked。每个chunk块由头部和正文两部分组成,头部中由一个16进制数字指定了正文的长度,最后一个长度为0的chunk块表示整个http正文结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java http
相关文章推荐