`
z1041950008
  • 浏览: 16709 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Http协议学习总结

    博客分类:
  • 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]为请求类型,请求类型有很多种,GETPOSTPUTDELETE等,用的最多就是GETPOST了。

 [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请求就可以看到了。说到这里,网上有很多讲GETPOST区别的,在我看来,有没有body部分,才是二者最大的区别。虽然没有body,但是报头下方依然有一个空行。



 

 

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



 

 

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

 

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

 

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

 

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



 

 

三、HTTP请求过程

 

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

 

非持久连接:

 

让我们查看一下非持久连接情况下从服务器到客户传送一个Web页面的步骤。假设该贝面由1个基本HTML文件和10JPEG图像构成,而且所有这些对象都存放在同一台服务器主机中。再假设该基本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文件。客户从中取出这个文件,加以分析后发现其中有10JPEG对象的引用。

 

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

 

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

 

持久连接:

 

      非持久连接的缺点

 

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

 

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

 

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

 

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

 

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

 

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

 

四、HTTP协议的使用

 

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

      •  使用JDK发送HTTP请求

 

package com.asiainfo.test;

 
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpTest {
    public static void readContentFromGet() throws IOException {

        URL getUrl = new URL(http://www.baidu.com);
        HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection();
        connection.connect();

        // 发送数据到服务器并使用Reader读取返回的数据
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

 
        String aline;
        while ((aline = reader.readLine()) != null) {
            System.out.println(aline);
        }
        reader.close();

 
        // 断开连接
        connection.disconnect();
    }

 

    public static void readContentFromPost() throws IOException {

        URL postUrl = new URL(http://www.baidu.com);
        HttpURLConnection connection = (HttpURLConnection) postUrl.openConnection();
        // 打开读写属性,默认均为false
        connection.setDoOutput(true);
        connection.setDoInput(true);
        // 设置请求方式,默认为GET
        connection.setRequestMethod("POST");
        connection.setUseCaches(false);
        // 配置连接的Content-type,配置为application/x-www-form-urlencoded的意思是正文是urlencoded编码过的form参数,
        //下面我们可以看到我们对正文内容使用URLEncoder.encode进行编码
        connection.setRequestProperty(" Content-Type "," application/x-www-form-urlencoded ");
        // 连接,从postUrl.openConnection()至此的配置必须要在 connect之前完成,
        // 要注意的是connection.getOutputStream()会隐含的进行调用 connect(),所以这里可以省略
        // connection.connect();
        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
        String content = "username=name&password=passwd";
        out.writeBytes(content);
        out.flush();
        out.close(); // flush and close
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String aline;
        while ((aline = reader.readLine()) != null) {
            System.out.println(aline);
        }
 
        reader.close();

    }

 
    public static void main(String[] args) {
        try {
            readContentFromGet();
            readContentFromPost();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
} 

 

 

 

  • 使用ApacheHttpClient发送Http请求

 

package com.zhuanqian.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.lang.StringUtils;
public class HttpUtil {
    public static HttpClient getHttpClient(){       HttpClient client = new HttpClient();
//     client.getHostConfiguration().setProxy("proxy.bmcc.com.cn", 8080);    
//     client.getParams().setAuthenticationPreemptive(true);    
//     //如果代理需要密码验证,这里设置用户名密码    
//     client.getState().setProxyCredentials(AuthScope.ANY, new UsernamePasswordCredentials("ngcrm_xubo","xcv.2134"));  
       client.getHttpConnectionManager().getParams().setConnectionTimeout(0);
       client.getHttpConnectionManager().getParams().setSoTimeout(0);
       return client;
    }

    public static HttpResponse doGet(String url) throws HttpException, IOException{
       HttpClient client = getHttpClient();
       GetMethod method = new GetMethod(url);       
       DefaultHttpMethodRetryHandler retry = new DefaultHttpMethodRetryHandler(0, false);       
       method.getParams().setParameter("http.method.retry-handler", retry);       
       method.getParams().setContentCharset("GB2312"); 
//      method.addRequestHeader("Content-Type", "text/html; charset=UTF-8");
       int status = client.executeMethod(method);
       HttpResponse response = new HttpResponse();       
       response.setStatusCode(status);       
       response.setResult(method.getResponseBodyAsString());       
       return response;
    } 
     public static HttpResponse doPost(String url, Map parameters, String json) throws Exception {

       HttpClient client = getHttpClient();
       PostMethod method = new PostMethod(url);
       DefaultHttpMethodRetryHandler retry = new DefaultHttpMethodRetryHandler(0, false);
       method.getParams().setParameter("http.method.retry-handler", retry);
       if(StringUtils.isNotBlank(json)){
          RequestEntity objRequestEntity = new ByteArrayRequestEntity(json.getBytes())
 					method.setRequestEntity(objRequestEntity);
 			 }
			 if(parameters != null && !parameters.isEmpty()){
          List list = new ArrayList();
          Set keys = parameters.keySet();
          String item;
          for(Iterator iter = keys.iterator(); iter.hasNext(); ){
              item = (String)iter.next();
              list.add(new NameValuePair(item, (String)parameters.get(item)));
          }
          method.setQueryString((NameValuePair[])list.toArray(new NameValuePair[0]));

      }
       int statusCode = client.executeMethod(method);
       HttpResponse response = new HttpResponse();
       response.setStatusCode(statusCode);
       response.setResult(method.getResponseBodyAsString());
       return response;
    }
}

 

 

 

 

五、HTTP协议之状态保持

 

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

 

      虽然HTTP协议本身是没有状态的,但是我们可以通过其他的手段来实现状态保持,最常用的就是CookieSessionSession也可以使用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接口,需要进行压力测试,因为觉得很简单,所以自己写了一个程序压了一下。发现过一段时间,就会报错,端口不足。代码如下:

 

        

while (true) {
   HttpClient client = new HttpClient();
   HttpMethod method = new GetMethod("http://www.apache.org");
   try {
    client.executeMethod(method);
    byte[] responseBody = method.getResponseBody();
   } catch (Exception e) {
    e.printStackTrace();
   }
  }

 

 

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

 

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

 

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

 

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

 

        

HttpClient client = new HttpClient();
  HttpMethod method = new GetMethod("http://www.apache.org");
  while (true) {
   try {
    client.executeMethod(method);
    byte[] responseBody = method.getResponseBody();
   } catch (Exception e) {
    e.printStackTrace();
   }
  }

 

 

      
 

 

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

 

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程序员的首选读物

 

 

 

 

  • 大小: 19.4 KB
  • 大小: 9.7 KB
  • 大小: 14.9 KB
  • 大小: 22.6 KB
3
0
分享到:
评论
4 楼 z1041950008 2015-03-09  
Cwind 写道
倒数第二段代码需要显式调用client.close()来关闭连接;GET用于获取资源,POST用于传输实体主体,还有PUT、DELETE等常用HTTP方法,应该通过方法意图来区分

Cwind 写道
倒数第二段代码需要显式调用client.close()来关闭连接;GET用于获取资源,POST用于传输实体主体,还有PUT、DELETE等常用HTTP方法,应该通过方法意图来区分


多谢提醒,因为没有用过PUT和DELETE,所以没敢写。怕写错了。
3 楼 Cwind 2015-03-09  
倒数第二段代码需要显式调用client.close()来关闭连接;GET用于获取资源,POST用于传输实体主体,还有PUT、DELETE等常用HTTP方法,应该通过方法意图来区分
2 楼 equals 2015-03-09  
大体浏览了下,感觉不错,标记一下,有时间来看看。
1 楼 nalan 2015-03-09  
好文章,中国就缺少这种基础性普及的文章,详细明白。楼猪加油了!

相关推荐

    http协议学习总结共10页.pdf.zip

    这份"HTTP协议学习总结共10页.pdf"的资料,很可能包含了对HTTP协议的全面概述,包括其原理、结构、请求方法、响应状态码、报文格式以及与HTTPS的区别等内容。 1. HTTP协议原理:HTTP协议是一种无状态、基于请求与...

    http协议学习总结协议格式消息头消息体等[参照].pdf

    HTTP 协议学习总结 HTTP 协议是一种通信协议,允许将超文本标记语言 (HTML) 文档从 Web 服务器传送到 Web 浏览器。它工作在 TCP/IP 协议体系中的 TCP 协议上,客户机和服务器必须都支持 HTTP,才能在万维网上发送和...

    C# 操作http协议学习总结下.docx

    【C# 操作HTTP协议学习总结】 在C#编程中,操作HTTP协议通常是网络通信的基础,用于发送和接收数据。System.Net.Http命名空间提供了一系列类和方法,使得开发者能够方便地进行HTTP请求和响应的处理。本文将重点讨论...

    HTTP协议学习笔记

    **HTTP协议概述** ...它是一个基于请求与响应模型的、无状态的、应用层协议...学习HTTP协议对于理解和优化Web应用至关重要。深入理解HTTP协议,可以帮助我们更好地利用Web资源,解决网络问题,以及开发更高效的Web服务。

    DNS协议分析和HTTP协议分析的实验报告.pdf

    通过对DNS和HTTP协议的深入分析,我们不仅能够理解这两种协议的基本工作原理和技术细节,还能够掌握如何使用Wireshark这样的工具来进行网络流量分析。这对于网络安全、性能优化等方面具有重要意义。希望本次实验能...

    HTTP协议的总结性内容,排版优美,便于学习.zip

    这个压缩包文件"HTTP协议的总结性内容,排版优美,便于学习.zip"包含了关于HTTP协议的详细知识,旨在帮助学习者更有效地理解和掌握这一基础网络协议。 1. **HTTP的基本概念**: - HTTP是一个基于TCP/IP通信协议来...

    HTTP协议详解PDF

    总结来说,这份"HTTP协议详解PDF"是学习HTTP协议的重要参考资料,它可以帮助开发者和网络从业者深入理解HTTP的工作方式,提高他们在Web开发和网络通信中的专业技能。同时,"更多电子资料.docx"可能是与HTTP协议相关...

    HTTP协议详解及RFC2616(HTTP)中文版

    **HTTP协议详解** HTTP(Hypertext Transfer Protocol)超文本传输协议是互联网上应用最广泛的一种网络协议。它是用于从万维网服务器传输超文本到本地浏览器的传输协议,是Web应用的基础。HTTP协议定义了客户端...

    HTTP协议详解PDF可打印版RFC2616

    总结,HTTP协议作为互联网的核心协议,理解其工作原理和细节至关重要。通过阅读和研究RFC2616,我们可以深入掌握HTTP/1.1的规范,从而更好地进行Web开发和网络通信设计。而这个PDF版本的文档,则为我们提供了便捷的...

    张孝祥_HTTP协议详解

    总结,张孝祥老师的HTTP协议详解课程涵盖了HTTP的基础概念、请求与响应机制、方法、状态码、头部字段等内容,对于理解和应用HTTP协议具有重要指导意义。通过深入学习,我们可以更好地理解和优化网络应用,提升用户...

    JavaWeb之http协议

    本文将围绕“JavaWeb之http协议”这一主题,结合提供的标签“源码”和“工具”,深入讲解HTTP协议的核心概念、工作原理以及在JavaWeb开发中的应用。 HTTP协议是一种应用层协议,基于TCP/IP通信协议来传输数据,主要...

    HTTP协议学习心得体会.docx

    ### HTTP协议学习心得体会 #### 一、HTTP协议简介 HTTP(HyperText Transfer Protocol)是一种用于传输超文本的应用层协议,它是互联网上应用最为广泛的一种网络协议。HTTP协议主要用于定义浏览器和Web服务器之间...

    http学习总结文档

    本文将深入探讨HTTP的学习总结,涵盖其基本概念、工作原理、请求方法、响应状态码、报文结构以及HTTP/1.1与HTTP/2的区别等核心知识点。 一、HTTP基础 HTTP是一种无状态、基于TCP/IP的协议,用于在Web上传输数据。无...

    张孝祥_HTTP协议详解第四讲

    总结来说,"张孝祥_HTTP协议详解第四讲"深入浅出地讲解了HTTP协议的关键要素,包括其工作原理、请求响应流程、请求方法、版本差异、状态码、安全性和缓存机制。通过这堂课的学习,我们可以更好地理解和应用HTTP协议...

    Web+HTTP+超文本传输协议核心总结 完整PDF

    超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送...本文档是一部HTTP协议的总结性内容,排版优美,便于学习,喜欢的朋友可以下载学习。

    HTTP协议和数据网络

    总结起来,HTTP协议是互联网上数据交换的基础,而数据网络则是这一切得以实现的物理和逻辑架构。理解这两者的工作原理对于网络开发和运维人员至关重要。通过深入学习和实践,我们可以更好地优化网络性能,解决网络...

    Java-HTTP协议讲解,使用初级人员入门学习

    #### 二、HTTP协议的工作原理 ##### 2.1 请求过程 当用户通过浏览器访问一个Web页面时,例如输入`www.example.com`,浏览器实际上会自动添加"http://"前缀,这是因为HTTP协议是浏览器默认使用的通信协议。浏览器...

Global site tag (gtag.js) - Google Analytics