客户端HTTP消息码流分析

在开发Web程序时,我们向Web服务发送请求是最常见的事,如果了解向服务器提交的HTTP码流,对有些问题我们就会有很好的把握,比如HTTP信息结构、乱码产生、表单参数以及URL绑定参数的传递提交机制,对我们提交的数据心中有数。下面我们就来看看通过表单与URL两种提交请求方式时各自的HTTP码流究竟如何?先来了解了解HTTP消息格式。

HTTP消息格式

HTTP报文是面向文本的,报文中的每一个字段都是一些ASCII码串,各个字段的长度是不确定的。HTTP有两类报文:请求报文和响应报文。

 

请求报文

 

一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成,下图给出了请求报文的一般格式。

 

 

 

 

 


 
1、请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1。


HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。这里介绍最常用的GET方法和POST方法。


GET:当客户端要从服务器中读取文档时,使用GET方法。GET方法要求服务器将URL定位的资源放在响应报文的数据部分,回送给客户端。使用GET方法时,请求参数和对应的值附加在URL后面,利用一个问号(“?”)代表URL的结尾与请求参数的开始,传递参数长度受限制。例如,/index.jsp?id=100&op=bind。


POST:当客户端给服务器提供信息较多时可以使用POST方法。POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据,可用来传送文件。

2、请求头部
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:
User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。

3、空行
最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
对于一个完整的http请求来说空行是必须的,否则服务器会认为本次请求的数据尚未完全发送到服务器,处于等待状态


4、请求数据
请求数据不在GET方法中使用,而是在POST方法中使用。POST方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。

 

 

 

 

 

 

了解了HTTP消息格式后,先我们要模拟服务器,让客户端往我们模拟服务器发送,这样我们就可以截获码流。下面是服务器模拟程序:

客户端HTTP码流端截取程序

 

import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.ServerSocket; import java.net.Socket; public class HttpServer { public static void main(String[] args) { try { ServerSocket sSocket = new ServerSocket(8088); Socket socket = sSocket.accept(); InputStream is = socket.getInputStream(); //String encode = "GB2312"; String encode = "UTF-8"; putStream(is, encode); } catch (IOException e) { e.printStackTrace(); } } public static void putStream(InputStream is, String encode) throws IOException, UnsupportedEncodingException { byte[] content = new byte[1024]; int readCount = is.read(content); OutputStreamWriter bos = new OutputStreamWriter(System.out); while (readCount != 0) { bos.write(new String(content, 0, readCount, encode)); bos.flush(); readCount = is.read(content); } is.close(); } }

 

 

POST方式提交表单并且URL后面绑定参数

JSP页面如下:

 

<%@ page language="java" contentType="text/html; charset=GB2312" pageEncoding="GB2312"%> <html> <body> <form name=form1 action="" method="post"> <input type="text" name="textParam1" size="50 px" value="中a ~!@#$%^&amp;*()_+{}|:\&quot; &lt;&gt;?`-=[]\\;',./"> <br> <input type="file" name="fileParam" size="50 px" value=""> <br> <input type="button" value="submit" οnclick="submitForm()"> </form> <script type="text/javascript"> function submitForm(){ var str ="中a ~!@#$%^&*()_+{}|:\" <>?`-=[]\\;',./"; //form1.action = "gb2312rs.jsp?qryParam1=" + encodeURIComponent(str) + "&qryParam2="+ encodeURIComponent(form1.textParam1.value) ; form1.action = "http://localhost:8088/gb2312rs.jsp?qryParam1=" + encodeURIComponent(str) + "&qryParam2="+ encodeURIComponent(form1.textParam1.value) ; form1.submit(); } </script> </body> </html>

 

 页面截图:


 

提交后地址栏如下:

http://localhost:8080/HttpStream/gb2312rs.jsp?qryParam1=%E4%B8%ADa%20~!%40%23%24%25%5E%26*()_%2B%7B%7D%7C%3A%22%20%3C%3E%3F%60-%3D%5B%5D%5C%3B'%2C.%2F&qryParam2=%E4%B8%ADa%20~!%40%23%24%25%5E%26*()_%2B%7B%7D%7C%3A%5C%22%20%3C%3E%3F%60-%3D%5B%5D%5C%5C%3B'%2C.%2F

HTTP消息码流:

POST /gb2312rs.jsp?qryParam1=%E4%B8%ADa%20~!%40%23%24%25%5E%26*()_%2B%7B%7D%7C%3A%22%20%3C%3E%3F%60-%3D%5B%5D%5C%3B'%2C.%2F&qryParam2=%E4%B8%ADa%20~!%40%23%24%25%5E%26*()_%2B%7B%7D%7C%3A%5C%22%20%3C%3E%3F%60-%3D%5B%5D%5C%5C%3B'%2C.%2F HTTP/1.1
Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer:
http://localhost:8080/HttpStream/gb2312.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8088
Content-Length: 132
Connection: Keep-Alive
Cache-Control: no-cache

 

textParam1=%D6%D0a+%7E%21@%23%24%25%5E%26*%28%29_%2B%7B%7D%7C%3A%5C%22+%3C%3E%3F%60-%3D%5B%5D%5C%5C%3B%27%2C.%2F&fileParam=file1.txt

从上面码流分析可知:

  • URL后绑定的参数会显示在HTTP消息头中。
  • 文件类型没有传到服务器,因为表单未设置enctype="multipart/form-data",但文件名却传过来了。
  • 提交请求为编码方式为GB2312的页面表单时,参数qryParam1与参数qryParam2都是UTF-8的编码格式,而不是以GBP312方式编码的,因此encodeURIComponent()函数是固定以UTF-8编码的,它不会受到当前浏览器的编码影响。
  • 经过encodeURIComponent()函数编码后的附加参数内容会以%xx形式串显示在地址栏中。
  • POST方式的HTTP头与HTTP体是用一个回车换行来分隔的。
  • POST方式提交表单,如果URL后面还附还参数,也会提交到服务器,且放在HTTP头部,其他表单输入元素会放在HTTP体里传送。
  • POST方式提交表单时,在头部会有 Content-Type: application/x-www-form-urlencoded 这样一个头信息,而GET方式提交的表单是不会有该头信息的,也不会有HTTP请求体。
  • POST方式提交时,表单里的元素值会先用浏览器的编码(这里使用的是GB2312编码)方式时行编码(a-z A-Z 0-9 +@*_-. 不进行编码),然后把编码转换成%xx(xx为两位的十六进制)形式参数串后传送到服务器。

GET方式提交表单

JSP页面如下:

与上面一样,只是表单提交方式改为 get。

页面截图:

与上面一样。

提交后地址栏如下:

http://localhost:8088/gb2312rs.jsp?textParam1=%D6%D0a+%7E%21@%23%24%25%5E%26*%28%29_%2B%7B%7D%7C%3A%5C%22+%3C%3E%3F%60-%3D%5B%5D%5C%5C%3B%27%2C.%2F&fileParam=file1.txt

HTTP消息码流:

GET /gb2312rs.jsp?textParam1=%D6%D0a+%7E%21@%23%24%25%5E%26*%28%29_%2B%7B%7D%7C%3A%5C%22+%3C%3E%3F%60-%3D%5B%5D%5C%5C%3B%27%2C.%2F&fileParamhttp://localhost:8080/HttpStream/gb2312.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0)
Accept-Encoding: gzip, deflate
Host: localhost:8088
Connection: Keep-Alive
=file1.txt HTTP/1.1
Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer:

 

从上面码流分析可知:

GET方式时,表单里的参数会先以浏览器编码成%XX形式后附加到URL后,并显示在地址栏中。 GET方式提交表单时,如果表单URL附加参数,这些参数是不能传递到服务器端去的,相反表单里的元素会附加在URL后面并传送到服务器,所以当提交表单时,如果表单URL还附加参数,则一定要以POST方式提交,否则是不能传递到服务器。 GET方式提交的请求HTTP头里没有  Content-Type: application/x-www-form-urlencoded  头信息。 GET提交时,表单里的元素值会先用浏览器的编码方式时行编码,然后把编码转换成%xx形式的串。

文件上传时HTTP码流

JSP页面如下:

<%@ page language="java" contentType="text/html; charset=GB2312" pageEncoding="GB2312"%> <html> <body> <form name=form1 action="" method="post" enctype="multipart/form-data"> <input type="text" name="textParam1" size="50 px" value="中a ~!@#$%^&amp;*()_+{}|:\&quot; &lt;&gt;?`-=[]\\;',./"> <br> <input type="file" name="fileParam1" size="50 px" value=""> <br> <input type="file" name="fileParam2" size="50 px" value=""> <br> <input type="button" value="submit" οnclick="submitForm()"> </form> <script type="text/javascript"> function submitForm(){ var str ="中a ~!@#$%^&*()_+{}|:\" <>?`-=[]\\;',./"; form1.action = "http://localhost:8088/gb2312rs.jsp?qryParam1=" + encodeURIComponent(str) + "&qryParam2="+ encodeURIComponent(form1.textParam1.value) ; form1.submit(); } </script> </body> </html>

 

  页面运行图:


 HTTP消息码流:

 

POST /gb2312rs.jsp?qryParam1=%E4%B8%ADa%20~!%40%23%24%25%5E%26*()_%2B%7B%7D%7C%3A%22%20%3C%3E%3F%60-%3D%5B%5D%5C%3B'%2C.%2F&qryParam2=%E4%B8%ADa%20~!%40%23%24%25%5E%26*()_%2B%7B%7D%7C%3A%5C%22%20%3C%3E%3F%60-%3D%5B%5D%5C%5C%3B'%2C.%2F HTTP/1.1
Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer:
http://localhost:8080/HttpStream/gb2312.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0)
Content-Type: multipart/form-data; boundary=---------------------------7d9165750396
Accept-Encoding: gzip, deflate
Host: localhost:8088
Content-Length: 595
Connection: Keep-Alive
Cache-Control: no-cache

 

-----------------------------7d9165750396
Content-Disposition: form-data; name="textParam1"

 

中a ~!@#$%^&*()_+{}|:\" <>?`-=[]\\;',./
-----------------------------7d9165750396
Content-Disposition: form-data; name="fileParam1"; filename="file1.txt"
Content-Type: text/plain

 

这是第一个测试文件的内容:
1111111111111
aaaaaaaaaaaaa
-----------------------------7d9165750396
Content-Disposition: form-data; name="fileParam2"; filename="file2.txt"
Content-Type: text/plain

 

这是第二个测试文件的内容:
中a
~!@#$%^&*()_+{}|:\" <>?`-=[]\\;',./
-----------------------------7d9165750396--

码流分析:

  • 文件上传时表单要设置 enctype="multipart/form-data" 属性。
  • 上传时文件与参数一起放置在HTTP体里传送,并且参数不组以%XX形式传送,而是经过浏览器编码后直接传送到服务器,但文件内容就不同了,浏览器读取要上传文件时,不会使用任何编码来读取,而是原样读取(即在上文件时浏览器是以字节流形式读取文件的,而不是以字符形式来读取的,否则会涉及到编码问题)后发往服务器(试想下,如果浏览读取上传文件时还经过了浏览器编码,那我们上传的非字符性文件会坏掉)。
  • 消息头含有Content-Length属性,它表示消息体的总体长度。

 

附件为码流文件

 

参考:

http://blog.csdn.net/yc0188/archive/2009/10/29/4741871.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值