Http协议学习总结(转)

 

因为项目中很多地方都与Http协议有关,零散的了解了一下Http协议,但是没有系统的学习过。

 

今天根据网上其他同学的整理,加上我的一些经验,我也整理了一份。当做学习记录吧。

 

 

  

一、什么是HTTP协议

 

HTTP,全名HyperText Transfer Protocol。因特网上应用最为广泛的一种网络协议。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。现在对与HTTP协议的应用已经很多了,浏览器上网,下载文件,服务器间通信等。

 

二、HTTP协议格式

 

如下图,一次完整的HTTP交易过程,是由HTTP请求和HTTP响应组成的。下面介绍下HTTP的报文格式。

 

 

 

HTTP请求消息:在HTTP请求中,第一行必须是一个请求行(request line),用来说明请求类型、要访问的资源以及使用的HTTP版本。紧接着是一个报头(header)小节,用来说明服务器要使用的附加信息。在首部之后是一个空行,再此之后可以添加任意的其他数据,称之为主体(body)。

 

如下图所示,为访问百度首页的请求:

 

1)   第一行为请求行,分为3个部分。

 

 [GET]为请求类型,请求类型有很多种,GET、POST、PUT、DELETE等,用的最多就是GET和POST了。

 [http://www.baidu.com/]为请求网址,网址后面可以跟请求参数,http://www.baidu.com/s?ie=utf-8&f=8

 [HTTP/1.1]为协议版本

 

 

2)   第二行到最后一行为报头。每一个报头域都是由名字+“:”+空格+值组成,消息报头域的名字是大小写无关的。HTTP协议定义了很多的报头,图片中看到的Accept,Host,Cookie只是其中的一部分。【关于HTTP headers的简要介绍,请查看:Quick reference to HTTP headers

 

3)   接下来应该是body部分,但是下图中没有,因为GET请求是没有body部分的,如果是POST请求就可以看到了。说到这里,网上有很多讲GET和POST区别的,在我看来,有没有body部分,才是二者最大的区别。虽然没有body,但是报头下方依然有一个空行。

 

 

下面的图是POST请求的例子,很清楚可以看到body部分。

 

 

HTTP响应消息:响应消息和请求消息很类似,第一行为状态行,接下来是报头,报头后为一行空行,下面是返回内容,同样称之为body。

 

下图为上面请求百度首页的响应报文。

 

1)第一行为状态行,分为是三个部分,第一部分协议版本,第二部分状态码,第三部分状态码描述。

 

2)接下来的报头和body,都与HTTP请求消息类似。

 

 

三、HTTP请求过程

 

HTTP支持两种建立连接的方式:非持久连接持久连接(HTTP1.1默认的连接方式为持久连接)。

 

非持久连接:

 

让我们查看一下非持久连接情况下从服务器到客户传送一个Web页面的步骤。假设该贝面由1个基本HTML文件和10个JPEG图像构成,而且所有这些对象都存放在同一台服务器主机中。再假设该基本HTML文件的URL为:http://www.baidu.com。

 

下面是具体步骡:

 

1)     HTTP客户初始化一个与服务器主机http://www.baidu.com中的HTTP服务器的TCP连接。HTTP服务器使用默认端口号80监听来自HTTP客户的连接建立请求。

 

2)     HTTP客户经由与TCP连接相关联的本地套接字发出—个HTTP请求消息。这个消息中包含路径名/somepath/index.html。

 

3)     HTTP服务器经由与TCP连接相关联的本地套接字接收这个请求消息,再从服务器主机的内存或硬盘中取出对象/somepath/index.html,经由同一个套接字发出包含该对象的响应消息。

 

4)     HTTP服务器告知TCP关闭这个TCP连接(不过TCP要到客户收到刚才这个响应消息之后才会真正终止这个连接)。

 

5)     HTTP客户经由同一个套接字接收这个响应消息。TCP连接随后终止。该消息标明所封装的对象是一个HTML文件。客户从中取出这个文件,加以分析后发现其中有10个JPEG对象的引用。

 

6)     给每一个引用到的JPEG对象重复步骡1-4。

 

上述步骤之所以称为使用非持久连接,原因是每次服务器发出一个对象后,相应的TCP连接就被关闭,也就是说每个连接都没有持续到可用于传送其他对象。每个TCP连接只用于传输一个请求消息和一个响应消息。就上述例子而言,用户每请求一次那个web页面,就产生11个TCP连接。

 

持久连接:

 

      非持久连接的缺点

 

1)     客户得为每个待请求的对象建立并维护一个新的连接。对于每个这样的连接,TCP得在客户端和服务器端分配TCP缓冲区,并维持TCP变量。对于有可能同时为来自数百个不同客户的请求提供服务的web服务器来说,这会严重增加其负担。

 

2)     如前所述,每个对象都有2个RTT的响应延长——一个RTT用于建立TCP连接,另—个RTT用于请求和接收对象。

 

3)     每个对象都遭受TCP缓启动,因为每个TCP连接都起始于缓启动阶段。不过并行TCP连接的使用能够部分减轻RTT延迟和缓启动延迟的影响。

 

      而在持久连接情况下,服务器在发出响应后让TCP连接继续打开着。同一对客户/服务器之间的后续请求和响应可以通过这个连接发送。整个Web页面(上例中为包含一个基本HTMLL文件和10个图像的页面)自不用说可以通过单个持久TCP连接发送:甚至存放在同一个服务器中的多个web页面也可以通过单个持久TCP连接发送。

 

   通常,HTTP服务器在某个连接闲置一段特定时间后关闭它,而这段时间通常是可以配置的。持久连接分为不带流水线(without pipelining)和带流水线(with pipelining)两个版本。如果是不带流水线的版本,那么客户只在收到前一个请求的响应后才发出新的请求。这种情况下,web页面所引用的每个对象(上例中的10个图像)都经历1个RTT的延迟,用于请求和接收该对象。与非持久连接2个RTT的延迟相比,不带流水线的持久连接已有所改善,不过带流水线的持久连接还能进一步降低响应延迟。不带流水线版本的另一个缺点是,服务器送出一个对象后开始等待下一个请求,而这个新请求却不能马上到达。这段时间服务器资源便闲置了。

 

      HTTP/1.1的默认模式使用带流水线的持久连接。这种情况下,HTTP客户每碰到一个引用就立即发出一个请求,因而HTTP客户可以一个接一个紧挨着发出各个引用对象的请求。服务器收到这些请求后,也可以一个接一个紧挨着发出各个对象。如果所有的请求和响应都是紧挨着发送的,那么所有引用到的对象一共只经历1个RTT的延迟(而不是像不带流水线的版本那样,每个引用到的对象都各有1个RTT的延迟)。另外,带流水线的持久连接中服务器空等请求的时间比较少。与非持久连接相比,持久连接(不论是否带流水线)除降低了1个RTT的响应延迟外,缓启动延迟也比较小。其原因在于既然各个对象使用同一个TCP连接,服务器发出第一个对象后就不必再以一开始的缓慢速率发送后续对象。相反,服务器可以按照第一个对象发送完毕时的速率开始发送下一个对象。    

 

四、HTTP协议的使用

 

      最常见的应用就是浏览器了,这个大家都会用。下面介绍下JAVA中如何发送HTTP请求。

      •  使用JDK发送HTTP请求

 

Java代码 

 

  1. package com.asiainfo.test;  
  2.   
  3.    
  4. import java.io.BufferedReader;  
  5. import java.io.DataOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStreamReader;  
  8. import java.net.HttpURLConnection;  
  9. import java.net.URL;  
  10.   
  11. public class HttpTest {  
  12.     public static void readContentFromGet() throws IOException {  
  13.   
  14.         URL getUrl = new URL(<a href="http://www.baidu.com">http://www.baidu.com</a>);  
  15.         HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection();  
  16.         connection.connect();  
  17.   
  18.         // 发送数据到服务器并使用Reader读取返回的数据  
  19.         BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));  
  20.   
  21.    
  22.         String aline;  
  23.         while ((aline = reader.readLine()) != null) {  
  24.             System.out.println(aline);  
  25.         }  
  26.         reader.close();  
  27.   
  28.    
  29.         // 断开连接  
  30.         connection.disconnect();  
  31.     }  
  32.   
  33.    
  34.   
  35.     public static void readContentFromPost() throws IOException {  
  36.   
  37.         URL postUrl = new URL(<a href="http://www.baidu.com">http://www.baidu.com</a>);  
  38.         HttpURLConnection connection = (HttpURLConnection) postUrl.openConnection();  
  39.         // 打开读写属性,默认均为false  
  40.         connection.setDoOutput(true);  
  41.         connection.setDoInput(true);  
  42.         // 设置请求方式,默认为GET  
  43.         connection.setRequestMethod("POST");  
  44.         connection.setUseCaches(false);  
  45.         // 配置连接的Content-type,配置为application/x-www-form-urlencoded的意思是正文是urlencoded编码过的form参数,  
  46.         //下面我们可以看到我们对正文内容使用URLEncoder.encode进行编码  
  47.         connection.setRequestProperty(" Content-Type "," application/x-www-form-urlencoded ");  
  48.         // 连接,从postUrl.openConnection()至此的配置必须要在 connect之前完成,  
  49.         // 要注意的是connection.getOutputStream()会隐含的进行调用 connect(),所以这里可以省略  
  50.         // connection.connect();  
  51.         DataOutputStream out = new DataOutputStream(connection.getOutputStream());  
  52.         String content = "username=name&password=passwd";  
  53.         out.writeBytes(content);  
  54.         out.flush();  
  55.         out.close(); // flush and close  
  56.         BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));  
  57.         String aline;  
  58.         while ((aline = reader.readLine()) != null) {  
  59.             System.out.println(aline);  
  60.         }  
  61.    
  62.         reader.close();  
  63.   
  64.     }  
  65.   
  66.    
  67.     public static void main(String[] args) {  
  68.         try {  
  69.             readContentFromGet();  
  70.             readContentFromPost();  
  71.         } catch (IOException e) {  
  72.             e.printStackTrace();  
  73.         }  
  74.     }  
  75.    
  76. }   

 

 

 

  • 使用Apache的HttpClient发送Http请求

 

Java代码 

 

  1. package com.zhuanqian.util;  
  2. import java.io.IOException;  
  3. import java.util.ArrayList;  
  4. import java.util.Iterator;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7. import java.util.Set;  
  8. import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;  
  9. import org.apache.commons.httpclient.HttpClient;  
  10. import org.apache.commons.httpclient.HttpException;  
  11. import org.apache.commons.httpclient.NameValuePair;  
  12. import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;  
  13. import org.apache.commons.httpclient.methods.GetMethod;  
  14. import org.apache.commons.httpclient.methods.PostMethod;  
  15. import org.apache.commons.httpclient.methods.RequestEntity;  
  16. import org.apache.commons.lang.StringUtils;  
  17. publicclass HttpUtil {  
  18.     publicstatic HttpClient getHttpClient(){       HttpClient client = new HttpClient();  
  19. //     client.getHostConfiguration().setProxy("proxy.bmcc.com.cn", 8080);      
  20. //     client.getParams().setAuthenticationPreemptive(true);      
  21. //     //如果代理需要密码验证,这里设置用户名密码      
  22. //     client.getState().setProxyCredentials(AuthScope.ANY, new UsernamePasswordCredentials("ngcrm_xubo","xcv.2134"));    
  23.        client.getHttpConnectionManager().getParams().setConnectionTimeout(0);  
  24.        client.getHttpConnectionManager().getParams().setSoTimeout(0);  
  25.        return client;  
  26.     }  
  27.   
  28.     publicstatic HttpResponse doGet(String url) throws HttpException, IOException{  
  29.        HttpClient client = getHttpClient();  
  30.        GetMethod method = new GetMethod(url);         
  31.        DefaultHttpMethodRetryHandler retry = new DefaultHttpMethodRetryHandler(0, false);         
  32.        method.getParams().setParameter("http.method.retry-handler", retry);         
  33.        method.getParams().setContentCharset("GB2312");   
  34. //      method.addRequestHeader("Content-Type", "text/html; charset=UTF-8");  
  35.        int status = client.executeMethod(method);  
  36.        HttpResponse response = new HttpResponse();         
  37.        response.setStatusCode(status);         
  38.        response.setResult(method.getResponseBodyAsString());         
  39.        return response;  
  40.     }   
  41.      publicstatic HttpResponse doPost(String url, Map parameters, String json) throws Exception {  
  42.   
  43.        HttpClient client = getHttpClient();  
  44.        PostMethod method = new PostMethod(url);  
  45.        DefaultHttpMethodRetryHandler retry = new DefaultHttpMethodRetryHandler(0, false);  
  46.        method.getParams().setParameter("http.method.retry-handler", retry);  
  47.        if(StringUtils.isNotBlank(json)){  
  48.           RequestEntity objRequestEntity = new ByteArrayRequestEntity(json.getBytes())  
  49.                     method.setRequestEntity(objRequestEntity);  
  50.              }  
  51.              if(parameters != null && !parameters.isEmpty()){  
  52.           List list = new ArrayList();  
  53.           Set keys = parameters.keySet();  
  54.           String item;  
  55.           for(Iterator iter = keys.iterator(); iter.hasNext(); ){  
  56.               item = (String)iter.next();  
  57.               list.add(new NameValuePair(item, (String)parameters.get(item)));  
  58.           }  
  59.           method.setQueryString((NameValuePair[])list.toArray(new NameValuePair[0]));  
  60.   
  61.       }  
  62.        int statusCode = client.executeMethod(method);  
  63.        HttpResponse response = new HttpResponse();  
  64.        response.setStatusCode(statusCode);  
  65.        response.setResult(method.getResponseBodyAsString());  
  66.        return response;  
  67.     }  
  68. }  

 

 

 

 

五、HTTP协议之状态保持

 

    无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。从另一方面讲,打开一个服务器上的网页和你之前打开这个服务器上的网页之间没有任何联系。

 

      虽然HTTP协议本身是没有状态的,但是我们可以通过其他的手段来实现状态保持,最常用的就是Cookie和Session。Session也可以使用Cookie来实现。

 

      Cookie机制:服务器在响应消息中通过Set-Cookie头将Cookie内容返回给客户端,客户端在新的请求中通过Cookie发送给服务器,从而实现了会话的保持。

 

      Session机制:Session是一种服务器机制,当客户端请求创建一个Session时,服务器首先检查请求中是否存在Session标识,如果有将根据此标识查找出来使用,如果查不到,或者Session已过期,则重新创建一个,然后将其返回给客户端使用。

 

六、HTTP协议之长连接

 

    HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是UDP协议(无连接)。

 

      从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。但是Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。

 

      之前就遇到过一个长连接引起的问题。当时项目部署有一个Http接口,需要进行压力测试,因为觉得很简单,所以自己写了一个程序压了一下。发现过一段时间,就会报错,端口不足。代码如下:

 

        

Java代码 

 

  1. while (true) {  
  2.    HttpClient client = new HttpClient();  
  3.    HttpMethod method = new GetMethod("http://www.apache.org");  
  4.    try {  
  5.     client.executeMethod(method);  
  6.     byte[] responseBody = method.getResponseBody();  
  7.    } catch (Exception e) {  
  8.     e.printStackTrace();  
  9.    }  
  10.   }  

 

 

   过检查才发现原因:method.releaseConnection()实际上没有关闭连接,只是将链接返回给了ConnectionManager,然后ConnectionManager会根据算法来关闭连接。

 

   这样当循环发起Http请求时,就会不断打开新端口,直到端口不足。然后参考网上其他同学的做法,主动将Connection断开后,发现本地还是端口还是不足,严重怀疑端口不能立即释放。

 

   后来想到,在使用jmeter进行压测的时候,从来没有出现过这种情况。好在jmeter是java写的,我就翻了翻jmeter的代码,终于找到了答案。

 

      原来秘诀在于,需要将HttpClient重复使用即可。于是代码优化成下面这样后,就完美运行无压力了。

 

        

Java代码 

 

  1. HttpClient client = new HttpClient();  
  2.   HttpMethod method = new GetMethod("http://www.apache.org");  
  3.   while (true) {  
  4.    try {  
  5.     client.executeMethod(method);  
  6.     byte[] responseBody = method.getResponseBody();  
  7.    } catch (Exception e) {  
  8.     e.printStackTrace();  
  9.    }  
  10.   }  

 

 

        

 

最后,这是有个网上有位同学建议的几本书,我也木有看过,记下来,万一哪天就能看懂了呢。哈哈

 

1.O'Reilly - HTTP Pocket Reference:这是一本比较简短的介绍HTTP协议的书,可以作为入门读物

 

2.O'Reilly - HTTP The Definitive Guide:这是一本宝典级别的书,因为它包含的内容实在多,可以作为全面学习的HTTP协议的首选读物

 

3.Sams - HTTP Developers Handbook:这是比HTTP The Definitive Guide稍微比HTTP The Definitive Guide简单。不过从我的感觉,这本书比HTTP The Definitive Guide要好,因为它篇幅比较少,介绍的是HTTP精髓,我认为这本书应该是web程序员的首选读物

http://z1041950008.iteye.com/blog/2190509

 

时间: 2025-01-02 14:12:27

Http协议学习总结(转)的相关文章

苹果ANCS协议学习【转】

  苹果ANCS协议学习 转自:http://www.cnblogs.com/alexcai/p/4321514.html 综述 苹果通知中心(Apple Notification Center Service, ANCS)的目的是提供给蓝牙外设一种简单.方便的获取ios设备通知信息的方式.   依赖 ANCS的使用没有依赖,它是GATT的一个子集,任何一个实现了GATT client的设备可以方便的从ios设备获取通知信息.   传输注意事项 如果没有特殊说明,通过ANCS传输的数值均使用小端

XMPP学习——3、XMPP协议学习补充

流基础 两个基本概念,使得XMPP实体之间的小的结构化信息有效载荷能快速地进行异步交换:XML流和XML节.这些术语的定义如下. XML流的定义: XML流是一个容器,用于任何两个实体通过网络进行XML元素的交换. XML流的开始明确表达为一个打开的 "流头" (即, 一个包含了适当树形和命名空间声明的 XML <stream> 标签), 而这个XML流的结尾明确表达为一个关闭的XML </stream> 标签. 在流的生存期间, 发起方实体可以通过这个流发送不

JavaWeb 后端 &lt;一&gt; 之 Tomcat服务器 - Http协议 学习笔记

1.Web开发概述 1.1服务器上的资源分类: a.静态资源:指web页面中供人们浏览的数据始终是不变.html css js 图片 多媒体 b.动态资源:指web页面中供人们浏览的数据是由程序产生的,不同时间点访问web页面看到的内容各不相同.JSP/Servlet.php.asp 下面为简单的java程序 模拟服务器提供资源 访问 本地端口1111即可得到服务器的资源 public class Myserver {     public static void main(String[] a

MQTT协议学习笔记

1.前沿 万物联网的时代即将到来,物联网也由当初的概念开始进一步落实.随着无线网络技术飞速发展,各种设备都可以连接网络,实现远程控制.例如智能家居最近非常火爆,智能插座.智能LED灯.智能摄像头等.在互联网时代,HTTP协议负责建立网络连接,而到了物联网时代,由于智能硬件的差异,相比互联网终端,硬件配置要低的多,而且智能设备的环境也想多复杂,物联网中的数据传输会面临很多问题,比如在网络不稳定的情况下,如果保证数据的传输没有问题,如何保证数据不被重复发送,连接断开后如何进行重连,而HTTP协议由于

http协议学习及Wireshark工具使用

1. 基础概念篇1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本.其中最著名的就是RFC 2616.RFC 2616定义了今天普遍使用的一个版本--HTTP 1.1. HTTP协议

RTP协议学习大总结从原理到代码

from:http://wenku.baidu.com/view/aaad3d136edb6f1aff001fa5.html   一.流媒体概念 流媒体包含广义和狭义两种内涵:广义上的流媒体指的是使音频和视频形成稳定和连续的传输流和回放流的一系列技术.方法和协议的总称,即流媒体技术:狭义上 的流媒体是相对于传统的下载-回放方式而言的,指的是一种从Internet上获取音频和视频等多媒体数据的新方法,它能够支持多媒体数据流的实时传输和 实时播放.通过运用流媒体技术,服务器能够向客户机发送稳定和连续

RTMP 协议学习总结

RTMP协议是一个互联网TCP/IP五层体系结构中应用层的协议.RTMP协议中基本的数据单元称为消息(Message).当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk). 1 消息 消息是RTMP协议中基本的数据单元.不同种类的消息包含不同的Message Type ID,代表不同的功能.RTMP协议中一共规定了十多种消息类型,分别发挥着不同的作用.例如,Message Type ID在1-7的消息用于协议控制,这些消息一般是RTMP协议自身管理要使用的

Cisco路由器OSPF协议学习技巧

本文主要给大家详细的介绍了路由器OSPF的协议设置,并且说明了该协议的功能作用,下面的文章将给予你详细的介绍.OSPF协议操作:1.宣告OSPF的路由器从所有启动OSPF协议的接口上发出HELLO报文,两台ROUTER共享一条公共数据链路,并且能够相互成功协商各自HELLO报文中所指定的参数. 那么它们就成为邻居(Neighbor)2.邻接关系(Adjacency)建立是交换HELLO报文信息的路由器类型和交换HELLO报文信息的网络类型决定的3.每一台ROUTER都会在所有形成邻接关系的邻居之

RTSP协议学习笔记

一.        RTSP协议概述 RTSP(Real-Time Stream Protocol )是一种基于文本的应用层协议,在语法及一些消息参数等方面,RTSP协议与HTTP协议类似. RTSP被用于建立的控制媒体流的传输,它为多媒体服务扮演"网络远程控制"的角色.尽管有时可以把RTSP控制信息和媒体数据流交织在一起传送,但一般情况RTSP本身并不用于转送媒体流数据.媒体数据的传送可通过RTP/RTCP等协议来完成. 一次基本的RTSP操作过程是:首先,客户端连接到流服务器并发送