【场景】

服务端点对点通知。
A服务发起请求B服务,B同步返回接收成功;然后B开始处理逻辑;B处理完成后异步通知给A;A接收请求并处理,同步回写响应给B;完成。

【先上代码】

服务端(接收端)代码:

  1. import javax.servlet.ServletException;
  2. import javax.servlet.http.HttpServlet;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpServletResponse;
  5. import java.io.IOException;
  6. import java.util.Map;
  7.  
  8. public class ServController extends HttpServlet {
  9.  
  10. @Override
  11. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  12. System.out.println("===============================");
  13.  
  14. try {
  15. Map<String, String[]> mapByRequest = request.getParameterMap();
  16. // Map mapByRequest = ReadHttpRequest.getRequestMap(request); //request.getParameterMap();
  17. System.out.println("map count:" + mapByRequest.size());
  18.  
  19. if(mapByRequest!=null && mapByRequest.size()>0) {
  20. System.out.println("map[0]:" + mapByRequest.keySet().toArray()[0]);
  21. }
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25.  
  26. // String requestString = ReadHttpRequest.getRequestInputStream(request);
  27. // System.out.println("requestString:" + requestString);
  28.  
  29. HtmlUtil.write(response, "success");
  30. }
  31.  
  32. @Override
  33. protected void doGet(HttpServletRequest request, HttpServletResponse response)
  34. throws ServletException, IOException {
  35. HtmlUtil.write(response, "this is doGet()");
  36. }
  37. }

客户端(请求端)HttpUtil工具类:

  1. import javax.net.ssl.HttpsURLConnection;
  2. import java.io.*;
  3. import java.net.HttpURLConnection;
  4. import java.net.SocketTimeoutException;
  5. import java.net.URL;
  6. import java.util.Map;
  7.  
  8. public class HttpUtil {
  9.  
  10. /**
  11. * 发送http请求并接收返回,字符集默认UTF-8
  12. *
  13. * @param url 请求地址
  14. * @param sendData 发送数据
  15. * @param connTimeOut 连接超时
  16. * @param readTimeOut 响应超时
  17. * @return 返回报文
  18. * @throws Exception
  19. */
  20. public static String sendAndRcvHttpPost(String url, String sendData, int connTimeOut, int readTimeOut) {
  21. return sendAndRcvHttpPost(url, sendData, "UTF-8", connTimeOut, readTimeOut, "");
  22. }
  23.  
  24. /**
  25. * 发送http请求并接收返回,(指定字符集)
  26. *
  27. * @param url 请求地址
  28. * @param sendData 发送数据
  29. * @param charset 字符集
  30. * @param connTimeOut 连接超时
  31. * @param readTimeOut 响应超时
  32. * @param lineSpliter 换行符
  33. * @return 返回报文
  34. * @throws Exception
  35. */
  36. public static String sendAndRcvHttpPost(String url, String sendData, String charset, int connTimeOut, int readTimeOut, String lineSpliter) {
  37. return sendAndRcvHttpPostBase(url, sendData, charset, connTimeOut, readTimeOut,
  38. "application/x-www-form-urlencoded;charset=" + charset,
  39. // "text/plain",
  40. null, lineSpliter);
  41. }
  42.  
  43. public static String sendAndRcvHttpPostBase(String url, String oriData, String charset, int connTimeOut, int readTimeOut,
  44. String contentType, Map<String, String> header, String lineSpliter) {
  45. Long curTime = System.currentTimeMillis();
  46. String tag = "@" + curTime;
  47. String result = "";
  48. BufferedReader in = null;
  49. DataOutputStream out = null;
  50. int code = 999;
  51. HttpsURLConnection httpsConn = null;
  52. HttpURLConnection httpConn = null;
  53. InputStream httpin = null;
  54. try {
  55. byte[] sendData = oriData.getBytes(charset);
  56. tag = sendData.hashCode() + tag;
  57. // Trace.logInfo(Trace.COMPONENT_HTTP, "SimpleHttpConnUtil Prepare:"+tag );
  58. URL myURL = new URL(url);
  59. // Trace.logInfo(Trace.COMPONENT_HTTP, "请求地址:"+url);
  60.  
  61. httpConn = (HttpURLConnection) myURL.openConnection();
  62. httpConn.setRequestProperty("Accept-Charset", charset);
  63. httpConn.setRequestProperty("user-agent", "Rich Powered/1.0");
  64. if (header != null) {
  65. for (String key : header.keySet()) {
  66. httpConn.setRequestProperty(key, (String) header.get(key));
  67. }
  68. }
  69. httpConn.setRequestMethod("POST");
  70. httpConn.setUseCaches(false);
  71. httpConn.setRequestProperty("Content-Type", contentType);
  72. httpConn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;");
  73. // httpConn.setRequestProperty("Accept-Encoding","gzip, deflate, sdch");
  74. httpConn.setRequestProperty("Accept-Language", "zh-CN,zh;");
  75. httpConn.setRequestProperty("Cache-Control", "no-cache");
  76. httpConn.setRequestProperty("Pragma", "no-cache");
  77. httpConn.setRequestProperty("Content-Length", sendData.length + "");
  78. httpConn.setConnectTimeout(connTimeOut);
  79. httpConn.setReadTimeout(readTimeOut);
  80. httpConn.setDoInput(true);
  81. httpConn.setInstanceFollowRedirects(true);
  82. if (sendData != null) {
  83. httpConn.setDoOutput(true);
  84. // 获取URLConnection对象对应的输出流
  85. try {
  86. httpConn.connect();
  87. } catch (Exception e) {
  88. e.printStackTrace();
  89. return null;
  90. }
  91. out = new DataOutputStream(httpConn.getOutputStream());
  92. // 发送请求参数
  93. out.write(sendData);
  94. // flush输出流的缓冲
  95. out.flush();
  96. out.close();
  97. }
  98. // 取得该连接的输入流,以读取响应内容
  99. code = httpConn.getResponseCode();
  100. httpin = httpConn.getInputStream();
  101.  
  102. if (HttpURLConnection.HTTP_OK == code) {
  103. String line;
  104.  
  105. in = new BufferedReader(new InputStreamReader(httpin, charset));
  106. while ((line = in.readLine()) != null) {
  107. result += line + lineSpliter;
  108. }
  109. } else {
  110. result = null;
  111. throw new Exception("支付失败,服务端响应码:" + code);
  112. }
  113. } catch (SocketTimeoutException e) {
  114. // Trace.logError(Trace.COMPONENT_ACTION, "获取返回报文超时!",e);
  115. result = "TO";
  116. } catch (Exception e) {
  117. // Trace.logError(Trace.COMPONENT_ACTION, "http通讯失败 !",e);
  118. result = null;
  119. } finally {
  120. // Trace.logInfo(Trace.COMPONENT_ACTION,"对方地址:"+url);
  121. if (out != null) {
  122. try {
  123. out.close();
  124. } catch (IOException e) {
  125. }
  126. }
  127. if (httpConn != null) {
  128. httpConn.disconnect();
  129. }
  130. if (httpsConn != null) {
  131. httpsConn.disconnect();
  132. }
  133. if (in != null) {
  134. try {
  135. in.close();
  136. } catch (IOException e) {
  137. }
  138. }
  139. }
  140. // Trace.logInfo(Trace.COMPONENT_HTTP, "SimpleHttpConnUtil "+tag+" end for "+(System.currentTimeMillis()-curTime)+"ms");
  141. return result;
  142. }
  143.  
  144. }

客户端测试方法:

  1. public class TestMain {
  2. public static void main(String[] args) {
  3. // String reqData ="p1=a&p2=b&p3=c";
  4. String reqData = "{\"interfaceName\":\"RegisterNotify\",\"merSignMsg\":\"APrWHHydX41atXjfadKBfDPUhKBQbZ6fTKcnHGtVBhe9qpSfArVqRFrlf2wgw9gzmMnGo3x15XKXAZnC51WU60FXNVj2kaxpWYzpuh6rvUDrDVQV6Z7SHEI8GvrMLE8uOG2TPR0Xu6v71o8u8TJsWsiVOP/ncsAHSzSz%%2B2Ch7N3E5ePCQi84To7LvSO5HrtUUmTbc%2BrmG2frJfYJNfvsxuGvt9U2MqmFeWFE98fK5e5SFUSSZLtqj42N18ppSZWSxN3MleGDTsy75zR3JxO6ol99lCPea4zqLmnUoEFlnJ3J6vXXUVXnMuSX5Mw%3D%3D\",\"merchantId\":\"M100002734\",\"tranData\":\"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iR0JLIiA%2FPjxCMkNSZXM%2BPHN0YXR1cz4wPC9zdGF0dXM%2BPGJpbmRTdHM%2BMTwvYmluZFN0cz48Y3VzdG9tZXJJZD5DMTAwMDE0Mjc1PC9jdXN0b21lcklkPjxjb21wYW55PtDs1t3TzrHpzOzPwsLD087Qxc%2Bi18nRr9PQz965q8u%2BPC9jb21wYW55PjxyZWZ1c2VSZWFzb24vPjwvQjJDUmVzPg%3D%3D\",\"version\":\"B2C1.0\"}";
  5. String reqUrl = "http://localhost:8080/test_tomcat_web_war_exploded/form03_6_2_Token_OpenCard_Back";
  6. // String reqUrl="http://localhost:8083/H5api/xx";
  7. String result = HttpUtil.sendAndRcvHttpPost(reqUrl, reqData, 100000, 1000000);
  8. System.out.println(result);
  9. }
  10. }

【测试结论】

Tomcat和jetty对于HttpServletRequest.getParameterMap()的处理不同。jetty可以直接获取到请求参数;而Tomcat获取不到。下面是Tomcat的日志:

  1. 六月 11, 2019 10:11:53 上午 org.apache.tomcat.util.http.Parameters processParameters
  2. 信息: Character decoding failed. Parameter [{"interfaceName":"RegisterNotify","merSignMsg":"APrWHHydX41atXjfadKBfDPUhKBQbZ6fTKcnHGtVBhe9qpSfArVqRFrlf2wgw9gzmMnGo3x15XKXAZnC51WU60FXNVj2kaxpWYzpuh6rvUDrDVQV6Z7SHEI8GvrMLE8uOG2TPR0Xu6v71o8u8TJsWsiVOP/ncsAHSzSz%%2B2Ch7N3E5ePCQi84To7LvSO5HrtUUmTbc%2BrmG2frJfYJNfvsxuGvt9U2MqmFeWFE98fK5e5SFUSSZLtqj42N18ppSZWSxN3MleGDTsy75zR3JxO6ol99lCPea4zqLmnUoEFlnJ3J6vXXUVXnMuSX5Mw%3D%3D","merchantId":"M100002734","tranData":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iR0JLIiA%2FPjxCMkNSZXM%2BPHN0YXR1cz4wPC9zdGF0dXM%2BPGJpbmRTdHM%2BMTwvYmluZFN0cz48Y3VzdG9tZXJJZD5DMTAwMDE0Mjc1PC9jdXN0b21lcklkPjxjb21wYW55PtDs1t3TzrHpzOzPwsLD087Qxc%2Bi18nRr9PQz965q8u%2BPC9jb21wYW55PjxyZWZ1c2VSZWFzb24vPjwvQjJDUmVzPg%3D%3D","version":"B2C1.0"}] with value [] has been ignored. Note that the name and value quoted here may be corrupted due to the failed decoding. Use debug level logging to see the original, non-corrupted values.
  3. Note: further occurrences of Parameter errors will be logged at DEBUG level.
  4.  
  5. map count:0

Character decoding failed.Parameter [dd] with value [] has been ignored. 百度翻译为:字符解码失败。已忽略值为[]的参数[dd]。

我的Tomcat版本是7.0.93;jetty版本是6.1.26。通过比较两者的servlet-api.jar,发现Tomcat7的servlet-api的版本是3.0,而jetty的servlet-api的版本是2.5。或许是这种版本的差异导致结果不同。试图跟踪源码来一识庐山真面目,jetty的进去了,但从RequestWapper类里也看不到什么;Tomcat的则进不去。

进一步通过Tomcat测试发现:对于请求参数里的merSignMsg,当我改变其值(去掉开头的一些字符)时,Tomcat就能获取到了。看来还是Tomcat处理字符编码的问题。

【话说回来】

话说回来,上面案例content-type用form实在不合适不地道,因为想获取到请求数据,得取key的值而不是value,这不符合常用的套路啊,由此我的同事那天在接收数据时很折腾了一番。像这种上送json字符串的,改用text/plain更合适,这样的话,接收端通过读取HttpServletRequest的输入流就可以获取到请求数据。

附上读取HttpServletRequest流的代码:

  1. package com;
  2.  
  3. import javax.servlet.http.HttpServletRequest;
  4. import java.io.*;
  5. import java.util.Arrays;
  6. import java.util.HashMap;
  7. import java.util.Iterator;
  8. import java.util.Map;
  9.  
  10. public class ReadHttpRequest {
  11.  
  12. /**
  13. * 从request.ParameterMap获取数据---适用于表单请求
  14. * @param request
  15. * @return
  16. * @throws UnsupportedEncodingException
  17. * @throws Exception
  18. */
  19. public static Map getRequestMap(HttpServletRequest request) throws UnsupportedEncodingException,Exception {
  20. Map result = new HashMap();
  21. Map<String, String[]> map = request.getParameterMap();
  22. if (0 == map.size()) {
  23. System.out.println("未获取到任何请求参数.");
  24. // throw new Exception("未获取到任何请求参数.");
  25. return result;
  26. }
  27.  
  28. for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
  29. Map.Entry element = (Map.Entry) iter.next();
  30. Object strKey = element.getKey(); //key值
  31. String[] value = (String[]) element.getValue(); //value,数组形式
  32. String values = "";
  33. for (int i = 0; i < value.length; i++) {
  34. values += "," + value[i];
  35. }
  36. result.put(strKey.toString(), values.replaceFirst(",", ""));
  37. }
  38. return result;
  39. }
  40.  
  41. /**
  42. * 从输入流获取数据---适用于流请求
  43. * @param request
  44. * @return
  45. */
  46. public static String getRequestInputStream(HttpServletRequest request) {
  47. InputStream in = null;
  48. ByteArrayOutputStream out = null;
  49. try {
  50. in = request.getInputStream();
  51. out = new ByteArrayOutputStream();
  52. in2OutStream(in, out, 1024 * 1024);
  53. return out.toString("UTF-8");
  54. } catch (UnsupportedEncodingException e) {
  55. e.printStackTrace();
  56. } catch (IOException e) {
  57. e.printStackTrace();
  58. } finally {
  59. try {
  60. if (out != null) out.close();
  61. } catch (IOException e) {
  62. e.printStackTrace();
  63. }
  64. try {
  65. if (in != null) in.close();
  66. } catch (IOException e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. return null;
  71. }
  72. private static void in2OutStream(InputStream in, OutputStream out,
  73. int bufferSize) throws IOException {
  74. byte[] buffer = new byte[bufferSize];// 缓冲区
  75. for (int bytesRead = 0; (bytesRead = in.read(buffer)) != -1; ) {
  76. out.write(buffer, 0, bytesRead);
  77. Arrays.fill(buffer, (byte) 0);
  78. }
  79. }
  80. }

▄︻┻┳═一tomcat与jetty接收请求参数的区别

▄︻┻┳═一比较两种方式的form请求提交

▄︻┻┳═一Post方式的Http流请求调用

tomcat与jetty接收请求参数的区别的更多相关文章

  1. springMVC中接收请求参数&&数据转发

    ### 1. 接收请求参数 #### 1.1. [不推荐] 通过HttpServletRequest获取请求参数 假设存在: <form action="handle_login.do ...

  2. SpringMVC——接收请求参数和页面传参

    Spring接收请求参数: 1.使用HttpServletRequest获取 @RequestMapping("/login.do") public String login(Ht ...

  3. struts2视频学习笔记 11-12(动态方法调用,接收请求参数)

    课时11 动态方法调用 如果Action中存在多个方法时,可以使用!+方法名调用指定方法.(不推荐使用) public String execute(){ setMsg("execute&q ...

  4. Struts系列笔记(6)---action接收请求参数

    action接收请求参数 在web开发中,去接收请求参数来获得表单信息非常的常见,自己也总结整理了有关Struts2通过action接收请求参数的几种方法. Struts2 提供三种数据封装的方式: ...

  5. struts2 action接收请求参数和类型转换

    1,action接收请求参数 在struts2中action是什么?(struts2是一个mvc框架)         V:jsp        M:action         C:action  ...

  6. Struts框架(6)---action接收请求参数

    action接收请求参数 在web开发中,去接收请求参数来获得表单信息非常的常见,自己也总结整理了有关Struts2通过action接收请求参数的几种方法. Struts2 提供三种数据封装的方式: ...

  7. SpringMVC之接收请求参数和页面传参

    1.Spring接收请求参数 1>.使用HttpServletRequest获取 @RequestMapping("/login.do") public String log ...

  8. action接收请求参数

    一.采用基本类型接收请求参数(get/post)在Action类中定义与请求参数同名的属性,struts2便能接收自动接收请求参数并赋给同名属性. action的代码: public class Pa ...

  9. SpringMVC接收请求参数和页面传参

    接收请求参数: 1,使用HttpServletRequest获取 @RequestMapping("/login.do") public String login(HttpServ ...

随机推荐

  1. Django 文件下载功能

    def file_download(request): con= MySQLdb.connect(host='192.168.xxx.xxx',user='root',passwd='xxxx',db ...

  2. [深入学习C#]C#实现多线程的方式:使用Parallel类

    简介 在C#中实现多线程的另一个方式是使用Parallel类.  在.NET4中 ,另一个新增的抽象线程是Parallel类 .这个类定义了并行的for和foreach的 静态方法.在为 for和 f ...

  3. javaScript-进阶篇(一)

    1.变量 1.必须以字母.下划线或美元符号开头,后面可以跟字母.下划线.美元符号和数字. 2.变量名区分大小写,如:A与a是两个不同变量. 3.不允许使用JavaScript关键字和保留字做变量名. ...

  4. codeforces 615E Hexagons (二分+找规律)

    E. Hexagons time limit per test 1 second memory limit per test 256 megabytes input standard input ou ...

  5. stl_list.h

    stl_list.h // Filename: stl_list.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: http://b ...

  6. 微信非全屏播放设置(仅Iphone)

    由于微信X5内核强制视频全屏,用X5自带内核播放,一般内嵌视频打开播放就会被全屏. ihpone里面可以通过设置 x-webkit-airplay="true" webkit-pl ...

  7. codevs 3372 选学霸

    3372 选学霸  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果 ...

  8. UILabel的富文本显示选项

    UILabel的富文本格式设置 1.实例化方法和使用方法 实例化方法: 使用字符串初始化 - (id)initWithString:(NSString *)str; 例: NSMutableAttri ...

  9. vc++ 访问php webService

    之前做了一个VC++访问c#制作的WebService,没有问题,接着我又做了一个VC++访问php制作的WebService ,结果老是出现Client错误.这个php WebService是用Ze ...

  10. bzoj 1070 修车 —— 费用流

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1070 需要考虑前面修的车对后面等待的车造成的时间增加: 其实可以从每个人修车的顺序考虑,如果 ...