HTTP协议

来源:互联网 发布:可米小子诅咒 知乎 编辑:程序博客网 时间:2024/05/22 01:46

什么是HTTP协议

HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程。客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一定的通讯格式,HTTP协议用于定义客户端与web服务器通迅的格式。
HTTP协议是学习JavaWeb开发的基石,不深入了解HTTP协议,就不能说掌握了WEB开发,更无法管理和维护一些复杂的WEB站点。

HTTP协议的版本

HTTP协议的版本:HTTP/1.0、HTTP/1.1。

HTTP1.0和HTTP1.1的区别

在HTTP1.0协议中,客户端与web服务器建立连接后,只能获得一个web资源。
HTTP1.1协议,允许客户端与web服务器建立连接后,在一个连接上获取多个web资源。
一个问题:一个web页面中,使用img标签引用了三幅图片,当客户端访问服务器中的这个web页面时,客户端总共会访问几次服务器,即向服务器发送了几次HTTP请求?
例,服务器中的web页面为1.html,内容为:

aaaaaaaaaaaaaaaaaaa<img src="1.jpg" /><img src="2.jpg" /><img src="3.jpg" />

此时通过浏览器访问服务器中的1.html。
这里写图片描述
可发现客户端向服务器发送了4次http请求,第一次获取到整个页面资源。第二次浏览器向服务器要1.jpg,然后依次向服务器要2.jpg、3.jpg。为了减少客户端向浏览器发送的请求数,减少服务器的压力,通常会利用css技术将多张图片归并为一张图片,请求时,只打开这张图片的一小部分。

HTTP请求

HTTP请求包括的内容

客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求。
一个完整的HTTP请求包括如下内容:

  • 一个请求行。
  • 若干请求头。
  • 实体内容。

范例:
这里写图片描述
Web服务器通过客户端发送过来的这些请求信息,就可以确定向请求者回送什么资源,以及根据客户端的环境信息采用什么方式进行回送等。

HTTP请求的细节——请求行

请求行中的GET称之为请求方式,请求方式有:

  • POST、GET、HEAD、OPTIONS、DELETE、TRACE、PUT
  • 常用的有: GET、 POST
  • 用户如没有设置,默认情况下浏览器向服务器发送的都是get请求,例如在浏览器直接输地址访问,点超链接访问等都是get,用户如想把请求方式改为post,可通过更改表单的提交方式实现。

不管POST或GET,都用于向服务器请求某个WEB资源,这两种方式的区别主要表现在数据传递上:

  • 如请求方式为GET方式,则可以在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔,例如:GET /mail/1.html?name=abc&password=xyz HTTP/1.1
    GET方式的特点:在URL地址后附带的参数是有限制的,其数据容量通常不能超过1K。
  • 如请求方式为POST方式,则可以在请求的实体内容中向服务器发送数据,POST方式的特点:传送的数据量无限制。

HTTP请求的细节——请求头

HTTP请求中的常用消息头。

  • Accept:用于告诉服务器,客户机支持的数据类型。
  • Accept-Charset:用于告诉服务器,客户机支持的编码。
  • Accept-Encoding:用于告诉服务器,客户机支持的数据压缩格式。
  • Accept-Language:客户机的语言环境。
  • Host:客户机通过这个头告诉服务器,想访问的主机名。
  • If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间。
  • Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的(用于防盗链上)。
  • User-Agent:客户机通过这个头告诉服务器,客户机的软件环境。
  • Cookie:客户机通过这个头可以向服务器带些数据。
  • Connection:客户机通过这个头告诉服务器,请求完了之后是保持连接(Keep-Alive)还是断开连接(close)。
  • Date:当前请求时间值。

例,

Host: localhost:8080User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateConnection: keep-aliveIf-Modified-Since: Thu, 07 Jul 2016 02:57:42 GMTIf-None-Match: W/"19-1467860262148"

HTTP响应

HTTP响应包括的内容

一个HTTP响应代表服务器向客户端回送的数据,它包括:

  • 一个状态行
  • 若干响应头
  • 实体内容

范例:
这里写图片描述
在一个HTTP响应中,WEB服务器通过响应头向web客户端描述客户端的请求成功与否,以及它所发送的数据类型等一些信息,客户端通过这些信息,进而可以知道如何对数据进行处理。

HTTP响应的细节——状态行

状态行格式:HTTP版本号 状态码 原因叙述<CRLF>。例:HTTP/1.1 200 OK
状态码用于表示服务器对请求的处理结果,它是一个三位的十进制数。响应状态码分为5类,如下所示:
这里写图片描述
这里还是细说几个常见的状态码:

  • 302——你是客户机,我是服务器,你请求我,我要你去找别人。要找哪个人,等一会我会给你回送一个location的头,location指定的是哪个地址,意味着要你去找谁。
  • 307/304:和缓存相关,你是客户机,我是服务器,你请求我,意味着我要你去拿缓存里面的数据显示。
  • 404——意味着请求的资源在web服务器里面没有,请求的地址可能写错了。
  • 403——你开始访问服务器某个资源,传入用户名和密码,结果用户名没有权限,服务器有这个资源,但拒绝给你这个资源。

HTTP响应细节——常用响应头

HTTP响应中的常用响应头(消息头):

  • location:这个头配合302状态码使用,用于告诉客户找谁。
  • Server:服务器通过这个头,告诉浏览器服务器的类型。
  • Content-Encoding:服务器通过这个头,告诉浏览器数据的压缩格式。
  • Content-Length:服务器通过这个头,告诉浏览器回送数据的长度。
  • Content-Language:服务器通过这个头,回送数据(即浏览器)的语言环境。
  • Content-Type:服务器通过这个头,告诉浏览器回送数据的类型。
  • Last-Modified:服务器通过这个头,告诉浏览器当前资源的缓存时间。
  • Refresh:服务器通过这个头,告诉浏览器隔多长时间刷新一次。
  • Content-Disposition:服务器通过这个头,告诉浏览器以下载方式打开数据。
  • Transfer-Encoding:服务器通过这个头,告诉浏览器数据的传送格式。
  • Set-Cookie:和Cookie相关的。以后会详讲。
  • ETag:缓存相关的头。
    服务器有很多web资源,每一个web资源根据其内容生成一个唯一的串(标识符),内容不同,标识符也不同。当浏览器访问服务器资源时,那服务器会把此资源的标识符以ETag方式的形式回写给客户机,客户机下次来访问服务器时,会带着ETag头来,服务器收到这个标识符之后,它会检查一下资源的标识符和客户机带过来的标识符是不是一样,如果是一样,意味着此资源没有被改动,没有被改动,直接就让浏览器去拿缓存;如果客户机带过来的标识符和服务器资源的标识符不一样,那么此资源就做出改动了,因为内容一改动,标识符就会跟着改,这时,服务器给浏览器回送改动后的资源。
    用ETag可以做到实时更新,其他头只能控制到秒一级的更新,无法做到实时性很高的系统。
  • Expires:服务器通过这个头,告诉浏览器把回送的资源缓存多长时间,-1或0,则不缓存。
  • Cache-Control: no-cache
  • Pragma: no-cache
    服务器通过以上两个头,也是控制浏览器不要缓存数据。(实时性要求很高的数据不能缓存,如股票数据,对于一般的数据,都可缓存。)
    如果控制市面上所有的浏览器都不要缓存数据,最好设置Expires、Cache-Control、Pragma这三个响应头
  • Connection:响应完之后,是保持连接,还是断开连接。
  • Date:当前响应时间值。

在服务端设置响应头来控制客户端浏览器的行为

新建一个动态web项目——day04,该项目的结构图如下:
这里写图片描述

设置Location响应头,实现请求重定向

@WebServlet("/ServletDemo1")public class ServletDemo1 extends HttpServlet {    // 用location和302实现请求重定向    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        response.setStatus(302);        response.setHeader("location", "/day04/1.html");    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        doGet(request, response);    }}

当在浏览器中使用URL地址http://localhost:8080/day04/ServletDemo1访问ServletDemo1时,就可以看到服务器作出响应后发送到浏览器的状态码和响应头信息,如下图所示:
这里写图片描述
服务器返回一个302状态码告诉浏览器,你要的资源我没有,但是我通过Location响应头告诉你哪里有,而浏览器解析响应头Location后知道要跳转到/day04/1.html页面,所以就会自动跳转到1.html,如下图所示:
这里写图片描述

设置Content-Encoding响应头,告诉浏览器数据的压缩格式

压缩数据的好处:

  1. 假设数据有1M,浏览器为了显示这个资源,要从服务器上下载1M的数据,才能打开整个页面,打开速度就慢,你如果一压缩,可能1M的数据只有300K,对浏览器而言,只需要接收300K的数据就可打开整个页面,所以压缩会提供整个页面的访问性能。
  2. 为了省钱,因为大型的网站,比如新浪、搜狐这样的门户网站,电信对它们的收费是按照出口流量收费的,出去了多少数据,电信找它们收多少钱,为了省钱,数据在发出去的时候一定要压缩,不压缩就亏大发了。

怎么实现数据的压缩?需要使用GZIPOutputStream流来压缩数据。

@WebServlet("/ServletDemo1")public class ServletDemo1 extends HttpServlet {    // 压缩数据输出    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        String data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+                      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+                      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+                      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+                      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";        System.out.println("原始数据大小:"+data.getBytes().length);        ByteArrayOutputStream bout = new ByteArrayOutputStream();        GZIPOutputStream gout = new GZIPOutputStream(bout);        gout.write(data.getBytes());        /*         * GZIPOutputStream:包装流,一般都会有一个缓冲,         * 如果调用其write()方法在写数据时,         * 如果数据量没有把包装流的缓冲写满,它是不会往底层流写的。         */        gout.close(); // 一定要有        // 得到压缩后的数据        byte[] gzip = bout.toByteArray();         System.out.println("压缩后的数据大小:"+gzip.length);        /*         * 将压缩数据发送给浏览器          */        // 通知浏览器数据采用压缩格式        response.setHeader("Content-Encoding", "gzip");        // 告诉浏览器回送的压缩数据的长度        response.setHeader("Content-Length", gzip.length+"");        response.getOutputStream().write(gzip);    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        doGet(request, response);    }}

服务器发给浏览器的响应信息如下:
这里写图片描述
此时Eclipse控制台打印如下信息:
这里写图片描述

设置content-type响应头,控制浏览器以哪种方式处理数据

@WebServlet("/ServletDemo1")public class ServletDemo1 extends HttpServlet {    // 通过Content-Type头字段,控制浏览器以哪种方式处理数据    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        response.setHeader("Content-Type", "image/jpeg");        // 读取位于项目根目录下的Krystal.jpg这张图片,返回一个输入流        InputStream in = this.getServletContext().getResourceAsStream("/Krystal.jpg");        int len = 0;        byte[] buffer = new byte[1024];        OutputStream out = response.getOutputStream();        while((len=in.read(buffer)) != -1) {            out.write(buffer, 0, len);        }    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        doGet(request, response);    }}

提示:Content-Type头字段对应的值可通过tomcat服务器下conf/web.xml文件查找。
服务器发给浏览器的响应信息如下:
这里写图片描述
ServletDemo1的运行结果如下图所示:
这里写图片描述
在浏览器中显示出了图片。

设置refresh响应头,让浏览器定时刷新

@WebServlet("/ServletDemo1")public class ServletDemo1 extends HttpServlet {    // 定时刷新    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        // response.setHeader("Refresh", "3"); // 浏览器每隔3秒钟请求一次        response.setHeader("Refresh", "3;url='http://www.sina.com'"); // 浏览器隔3秒钟请求一次后,并刷新到新浪上去        String data = "aaaaaaaaaaaaaaaaaaaaaaaa";        response.getOutputStream().write(data.getBytes());    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        doGet(request, response);    }}

设置content-disposition响应头,让浏览器下载文件

@WebServlet("/ServletDemo1")public class ServletDemo1 extends HttpServlet {    // 定时刷新    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        response.setHeader("Content-Disposition", "attachment;filename=Krystal.jpg");        InputStream in = this.getServletContext().getResourceAsStream("/Krystal(4).jpg");        int len = 0;        byte[] buffer = new byte[1024];        OutputStream out = response.getOutputStream();        while((len=in.read(buffer)) != -1) {            out.write(buffer, 0, len);        }    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        doGet(request, response);    }}

在浏览器中访问ServletDemo1就会弹出文件下载框,如下图所示:
这里写图片描述
可保存到桌面上。

HTTP的一个实用头字段——Range

HTTP请求头字段

Range头指示服务器只传输一部分web资源。这个头可以用来实现断点续传功能。Range字段可以通过三种格式设置要传输的字节范围:

  • Range:bytes=1000-2000
    传输范围从1000到2000字节。
  • Range:bytes=1000-
    传输web资源中第1000个字节以后的所有内容。
  • Range:bytes=1000
    传输最后1000个字节。

例,web服务器有一个资源,比如是a.txt,内容为:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

有一个用户下载了一部分数据,并存储到C盘中的a.txt,内容为:

aaaaa

此时该用户想接着下载完剩下的数据,该怎么做呢?此时他就不能通过浏览器去访问了,而应该自己写程序去访问指定的资源。

public class RangeDemo {    public static void main(String[] args) throws Exception {        URL url = new URL("http://localhost:8080/day04/a.txt");        HttpURLConnection conn = (HttpURLConnection) url.openConnection();        conn.setRequestProperty("Range", "bytes=5-");        InputStream in = conn.getInputStream();        int len = 0;        byte[] buffer = new byte[1024];        FileOutputStream out = new FileOutputStream("c:\\a.txt", true);        while((len=in.read(buffer)) != -1) {            out.write(buffer, 0, len);        }        in.close();        out.close();    }}

运行以上程序,该用户就下载完剩下的数据了。

HTTP响应头字段

Accept-Ranges:这个字段说明web服务器是否支持Range,支持则返回Accept-Ranges: bytes;如果不支持,则返回Accept-Ranges: none
Content-Range:指定了返回的web资源的字节范围。这个字段值的格式是——例,Content-Range: 1000-3000/5000
注意:HTTP响应头字段不常用。

0 0
原创粉丝点击