Socket实现的HTTP协议查看器(GET/POST/UPLOAD)

本文通过一个简单的Socket实现的HTTP响应服务器,介绍了GET、POST和文件上传三种表单提交方式的数据格式,帮助初学者熟悉HTTP协议。

本文用于初学者熟悉Http协议的一些细节,特别是常见的GET/POST(Upload)三种表单提交方式的数据格式。
原文地址: http://www.java2000.net/p9925

代码如下
  1. package test.io;
  2. import java.net.*;
  3. import java.io.*;
  4. /**
  5.  * 一个简单的Socket实现的HTTP响应服务器。<br>
  6.  * 只用于熟悉HTTP协议的目的,可以看到浏览器发过来的数据格式。
  7.  * 
  8.  * @author 赵学庆 www.java2000.net
  9.  */
  10. public class MyWebServer {
  11.   public static void main(String[] args) {
  12.     Socket socket = null;
  13.     try {
  14.       // 创建一个监听8000端口的服务器Socket
  15.       ServerSocket s = new ServerSocket(80003);
  16.       System.out.println("MyWebServer等待来自浏览器的连接/n");
  17.       while (true) {
  18.         socket = s.accept();
  19.         System.out.println("连接已建立。端口号:" + socket.getPort());
  20.         new MyWebServerThread(socket).start();
  21.       }
  22.     } catch (IOException e) {
  23.       e.printStackTrace();
  24.     }
  25.   }
  26. }
  27. class MyWebServerThread extends Thread {
  28.   private Socket socket;
  29.   MyWebServerThread(Socket socket) {
  30.     this.socket = socket;
  31.   }
  32.   @Override
  33.   public void run() {
  34.     try {
  35.       InputStreamReader is = new InputStreamReader(socket.getInputStream());
  36.       char[] bs = new char[2048];
  37.       PrintStream out;
  38.       out = new PrintStream(socket.getOutputStream());
  39.       StringBuilder msg = new StringBuilder();
  40.       // 如果10毫秒还没有数据,则视同没有新的数据了。
  41.       // 因为有Keep-Alive的缘故,浏览器可能不主动断开连接的。
  42.       // 实际应用,会根据协议第一行是GET还是 POST确定。
  43.       socket.setSoTimeout(10);
  44.       //
  45.       // 此处读入请求数据并做相应的处理
  46.       //
  47.       int len = -1;
  48.       try {
  49.         while ((len = is.read(bs)) != -1) {
  50.           msg.append(bs, 0, len);
  51.           msg.append("/n");
  52.         }
  53.       } catch (Exception ex) {
  54.         // ex.printStackTrace();
  55.       }
  56.       // 下面是由服务器直接生成的主页内容
  57.       // 1、首先向浏览器输出响应头信息
  58.       out.println("HTTP/1.1 200 OK");
  59.       out.println("Content-Type:text/html;charset:GBK");
  60.       out.println();
  61.       // 2、输出主页信息
  62.       out
  63.           .println("<HTML><BODY>"
  64.               + "<center>"
  65.               + "<H1>HTTP协议测试服务器,当前时间:"
  66.               + new java.util.Date()
  67.               + "</h1>"
  68.               + "<form method='get'>username:<input type='text' name='username'/>password:<input type='text' name='password'/><input type='submit' value='GET测试'/></form><br/>"
  69.               + "<form method='post'>username:<input type='text' name='username'/>password:<input type='text' name='password'/><input type='submit' value='POST测试'/></form><br/>"
  70.               + "<form method='post'  enctype='multipart/form-data'>phototitle:<input type='text' name='phototitle'/>photo:<input type='file' name='photo'/><input type='submit' value='Upload测试'/></form>"
  71.               + "</center>您提交的数据如下:<pre>" + msg.toString() + "</pre></BODY></HTML>");
  72.       out.flush();
  73.       out.close();
  74.       is.close();
  75.       System.out.println("close");
  76.       // 关闭连接
  77.       socket.close();
  78.     } catch (IOException e) {
  79.       e.printStackTrace();
  80.     }
  81.   }
  82. }

GET的运行结果演示
  1. GET /?username=111&password=222 HTTP/1.1
  2. Host: 127.0.0.1:8000
  3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: zh-cn,zh;q=0.5
  6. Accept-Encoding: gzip,deflate
  7. Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7
  8. Keep-Alive: 300
  9. Connection: keep-alive
  10. Referer: http://127.0.0.1:8000/?username=1&password=2 

普通POST的结果演示
  1. POST /?username=111&password=222 HTTP/1.1
  2. Host: 127.0.0.1:8000
  3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: zh-cn,zh;q=0.5
  6. Accept-Encoding: gzip,deflate
  7. Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7
  8. Keep-Alive: 300
  9. Connection: keep-alive
  10. Referer: http://127.0.0.1:8000/?username=111&password=222
  11. Content-Type: application/x-www-form-urlencoded
  12. Content-Length: 25
  13. username=111&password=222

POST文件上传的结果演示
  1. POST /?username=111&password=222 HTTP/1.1
  2. Host: 127.0.0.1:8000
  3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: zh-cn,zh;q=0.5
  6. Accept-Encoding: gzip,deflate
  7. Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7
  8. Keep-Alive: 300
  9. Connection: keep-alive
  10. Referer: http://127.0.0.1:8000/?username=111&password=222
  11. Content-Type: multipart/form-data; boundary=---------------------------23757983230932
  12. Content-Length: 1704
  13. -----------------------------23757983230932
  14. Content-Disposition: form-data; name="phototitle"
  15. 12
  16. -----------------------------23757983230932
  17. Content-Disposition: form-data; name="photo"filename="技术考核题.txt"
  18. Content-Type: text/plain
  19. 技术考核
  20. 本次是个编程题,题目选Java/语言进行回答。
  21. 问题描述:
  22. 假设你的爱好是集邮。目前总共有N种不同的邮票,编号为从0到N-1.每种邮票的价钱被定义在数组int[] prices中(序号从0开始,数组的第i个元素表示第i种邮票的价格)。
  23. 你的目标是收集尽可能多种的邮票。你当前拥有的邮票存储在int[] have这个数组中。初始时,你没有钱,但是你可以卖掉已有邮票来买不同的邮票。返回你能收集到的不同种邮票的最大数量。
  24. 定义:
  25. class: PostmarksCollection
  26. method: numberOfDistinctPostmarks
  27. Parameters: int[], int[]
  28. Returns: int
  29. Method signature: public int numberOfDistinctPostmarks(int[] prices, int[] have)
  30. //为了进行测试,必须保证是public
  31. 约束:
  32. 1) N从1到50
  33. 2)prices中的元素数量刚好是N个元素
  34. 3)prices中的元素的值,从1到1,000,000
  35. 4)have中的元素数量是0个到N个
  36. 5)have中的每个元素是不同的
  37. 6)have中的每个元素的值是从0到N-1.
  38. 例如:
  39. 1)
  40. {13,10,14,20}
  41. {3,0,2,1}
  42. Returns: 4
  43. 你已经拥有所有种类的邮票。
  44. 2)
  45. {7,5,9,7}
  46. {}
  47. Returns: 0
  48. 你开始没有任何邮票,所以你也不能组任何事情。
  49. 3)
  50. {4,13,9,1,5}
  51. {1,3,2}
  52. Returns: 4
  53. 卖掉邮票2,买入邮票0和4,(邮票2的价钱是9,邮票0的价钱是4,邮票4的价钱是5,卖掉2刚好买入0和4)
  54. 4)
  55. {16,32,13,2,17,10,8,8,20,17}
  56. {7,0,4,1,6,8}
  57. Returns: 8
  58. --------------------------------------------------------------------------------
  59. 使用Java请在此处答题(请使用JDK5.0编译,编译不能通过者不计算分数)
  60. -----------------------------23757983230932--

总结:
  初学者要提高自己的编程水平,熟悉一下常用的协议是必须的。

<think>我们正在处理Tomcat连接器参数配置不生效的问题。根据用户的问题,他想配置Tomcat Connector的参数(maxParameterCount, maxHttpHeaderSize,maxPostSize,maxSwallowSize)来解决请求参数和文件数量限制问题,但发现配置不生效。根据引用[3]中的内容,Tomcat的配置主要在conf文件夹下的配置文件中进行,特别是server.xml中的Connector配置。常见配置参数说明:1. maxParameterCount:限制请求参数(包括GETPOST)的最大数量。默认值为10000(Tomcat8.5+)。2.maxHttpHeaderSize:限制HTTP请求头的大小。默认值为8192(8KB)。3.maxPostSize:限制POST请求的最大大小(包括文件上传和表单数据)。如果设置为0,则表示不限制;负数表示不限制(但通常使用0);默认值为2097152(2MB)。4. maxSwallowSize:当请求被中止时,Tomcat会继续读取并忽略(吞下)的请求体最大字节数(不包括传输编码的开销)。默认值为2097152(2MB)。如果设置为负数,则表示不限制。用户反馈这些配置不生效,可能的原因和解决方法如下:1.**配置位置错误**:必须将配置放在Tomcat的conf/server.xml文件中的Connector标签内。例如:```xml<Connectorport="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"maxParameterCount="2000"maxHttpHeaderSize="16384"maxPostSize="4194304"maxSwallowSize="4194304"/>```2.**未重启Tomcat**:修改配置后必须重启Tomcat服务。3. **参数值设置错误**:注意参数值的单位是字节。例如,maxPostSize设置为4MB应该是4194304(4*1024*1024)。4. **配置被覆盖**:检查是否在多个地方配置了同一个参数,可能后面的配置覆盖了前面的配置。确保只在一个Connector中配置。5. **版本差异**:不同版本的Tomcat参数默认值可能不同,请确认Tomcat版本。例如,maxParameterCount在Tomcat7.0.70之前默认值是10000,但在某些旧版本中可能没有这个参数(需要升级)。6.**其他配置冲突**:如果使用了Spring框架,还需要注意Spring的Multipart配置(如MultipartConfigElement)可能会影响文件上传的限制。但请注意,maxPostSize是Tomcat层面的限制,会先于Spring的配置被处理。7. **日志检查**:查看Tomcat的日志(catalina.out或localhost.log)是否有错误信息,比如配置参数名错误,Tomcat在启动时可能会报告无法识别的属性。8.**参数名拼写错误**:确保参数名正确,例如是`maxParameterCount`而不是`maxParametersCount`(注意没有's')。9. **多个Connector**:如果配置了多个Connector(例如HTTP和AJP),确保修改的是正确的Connector(通常是HTTP的Connector)。10. **使用正确的协议**:确保在正确的协议Connector上配置。例如,如果是HTTP请求,则配置HTTP/1.1的Connector;如果是AJP,则配置AJP的Connector。11.**maxSwallowSize的特殊性**:这个参数只在请求被中止时(例如客户端在上传文件过程中断开连接)才起作用。正常情况下,如果客户端完整上传,这个参数不会生效。如果以上都检查无误,但问题仍然存在,可以尝试以下步骤: -使用一个简单的测试用例(如使用curl或Postman发送一个超过限制的请求)来验证配置是否生效。-确保测试的请求确实触发了相关限制(例如,测试maxParameterCount时,发送一个带有大量参数的GET请求;测试maxPostSize时,发送一个超过限制的POST请求)。另外,引用[1]中提到maxSwallowSize的默认值为2097152(2MB),如果上传的文件超过2MB并且在上传过程中客户端断开,Tomcat会吞下最多2MB的数据。如果设置更大的值,可以防止Tomcat因为处理大文件上传中断而导致的连接无法立即释放的问题。引用[2]中提到的错误(Addressalready inuse)通常与端口占用有关,与当前问题无关。引用[4]提到的@InitBinder是Spring MVC中的配置,用于数据绑定,与Tomcat容器配置无关。因此,重点应放在Tomcat的server.xml配置上。总结步骤:1.打开Tomcat的conf/server.xml文件。2.找到HTTPConnector(通常是port="8080"的Connector)。3.添加或修改四个参数:maxParameterCount,maxHttpHeaderSize, maxPostSize, maxSwallowSize,并设置合适的值(注意单位是字节)。4.保存文件并重启Tomcat。5.通过测试验证配置是否生效。如果仍然不生效,请检查Tomcat版本,并查阅对应版本的官方文档,确认这些参数在该版本中是否存在。注意:在Tomcat7中,maxPostSize参数的单位可能有些特殊,设置为0表示不限制,正数表示字节数,但注意在Tomcat7.0.63之前,maxPostSize的值如果大于Integer.MAX_VALUE(2147483647)会被认为是不限制,而Tomcat7.0.63及以后版本使用长整型,所以可以设置更大的值。在Tomcat8以后,这些参数都是长整型。示例配置(Tomcat8.5以上):```xml<Connector port="8080"protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"maxParameterCount="5000"maxHttpHeaderSize="32768"maxPostSize="8388608"maxSwallowSize="8388608" />```这个配置将:-最大参数数量设置为5000-最大HTTP头大小为32KB-最大POST请求大小为8MB-最大吞下大小为8MB最后,请确保在修改配置文件前备份server.xml,以防配置错误导致Tomcat无法启动。</think>### 配置 Tomcat Connector 参数解决限制问题 以下是针对 Tomcat 连接器参数配置不生效的完整解决方案,结合引用内容和实际配置经验: #### 核心参数说明 | 参数 | 作用 | 默认值 | 推荐值 | |------|------|--------|--------| | `maxParameterCount` | 限制请求参数数量 | 1000 | 2000-5000 | | `maxHttpHeaderSize` | HTTP 头最大尺寸 | 8KB | 16-32KB | | `maxPostSize` | POST 数据最大尺寸 | 2MB | 10-100MB | | `maxSwallowSize` | 中止上传时吞下的最大字节数 | 2MB | 与 maxPostSize 一致 | #### 正确配置方法(server.xml) ```xml <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" <!-- 关键参数配置 --> maxParameterCount="5000" maxHttpHeaderSize="32768" <!-- 32KB --> maxPostSize="104857600" <!-- 100MB --> maxSwallowSize="104857600" <!-- 100MB --> <!-- 性能优化参数 --> maxThreads="200" acceptCount="100" socket.rxBufSize="65536" socket.txBufSize="65536"/> ``` [^1][^3] #### 配置不生效的常见原因及解决 1. **位置错误** - ✅ 必须配置在 **主 Connector** 中(通常是 8080 端口) - ❌ 不要放在 AJP Connector 或备用 Connector 2. **单位混淆** - 所有尺寸参数单位都是 **字节(Byte)** - 正确示例:100MB = `100 * 1024 * 1024 = 104857600` 3. **特殊值规则** ```xml <!-- 特殊值含义 --> maxPostSize="0" <!-- 无限制 --> maxPostSize="-1" <!-- 旧版本Tomcat表示无限制 --> maxSwallowSize="-1" <!-- 无限制 --> ``` 4. **版本兼容性** | 参数 | 引入版本 | 注意事项 | |------|----------|----------| | maxParameterCount | Tomcat 7.0.84+ | 旧版本需升级 | | maxSwallowSize | Tomcat 7.0.64+ | 低于此版本无效 | 5. **冲突配置** - 检查是否被其他配置覆盖: - `conf/web.xml` 中的 `multipart-config` - Spring 的 `MultipartConfigElement` - 解决方案:删除冲突配置或确保 Tomcat 配置优先级更高 #### 验证配置是否生效 1. **查看启动日志** ```log INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] Parameters: maxPostSize=104857600, maxSwallowSize=104857600... ``` 2. **测试脚本** ```bash # 测试参数数量限制 curl "http://localhost:8080/test?$(seq -f 'p%g=1' 1 6000 | tr '\n' '&')" # 测试POST大小限制 dd if=/dev/zero bs=1M count=101 | curl -X POST http://localhost:8080/upload -T - ``` 预期结果: - 参数超过 5000 → 返回 400 Bad Request - POST 超过 100MB → 返回 413 Request Entity Too Large 3. **JMeter 压测验证** ```xml <!-- JMeter测试计划片段 --> <HTTPSamplerProxy> <elementProp name="HTTPsampler.Arguments"> <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <stringProp name="Argument.value">${__RandomString(1000000)}</stringProp> </elementProp> </collectionProp> </elementProp> </HTTPSamplerProxy> ``` [^2] #### 高级调试技巧 1. **启用详细日志** ```properties # conf/logging.properties org.apache.tomcat.util.http.Parameters.level = FINE org.apache.coyote.http11.level = ALL ``` 2. **检查配置继承** ```xml <!-- 确保没有父标签覆盖配置 --> <Service name="Catalina"> <Engine ...> <Host ...> <!-- 此处配置不会影响全局 --> </Host> </Engine> </Service> ``` 3. **使用 JConsole 监控** ```bash jconsole $(pgrep -f tomcat) ``` 查看 `org.apache.tomcat.util.net` 下的 MBean 属性 #### 典型问题解决方案 **问题:maxSwallowSize 不生效** 原因:当上传中断时,Tomcat 会强制断开连接而不处理响应[^1] 解决方案: 1. 确保 `maxSwallowSize >= maxPostSize` 2. 添加错误处理过滤器: ```java public class UploadErrorFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { try { chain.doFilter(req, res); } catch (IOException ex) { if (ex.getMessage().contains("Connection reset")) { // 处理客户端中断 res.getWriter().write("UPLOAD_ABORTED"); } } } } ``` **问题:maxParameterCount 对 POST 无效** 原因:POST 参数不受此限制(仅影响 URL 参数) 替代方案:使用 `maxPostSize` 限制整体请求体大小 > **关键提示**:生产环境建议配合 Nginx 前端限制: > ```nginx > http { > client_max_body_size 100m; > large_client_header_buffers 4 32k; > } > ``` > [^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值