zoukankan      html  css  js  c++  java
  • tomcat与jetty接收请求参数的区别

    【场景】

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

    【先上代码】

    服务端(接收端)代码: 

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Map;
    
    public class ServController extends HttpServlet {
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("===============================");
            
    
            try {
                Map<String, String[]> mapByRequest = request.getParameterMap();
    //            Map mapByRequest = ReadHttpRequest.getRequestMap(request); //request.getParameterMap();
                System.out.println("map count:" + mapByRequest.size());
    
                if(mapByRequest!=null && mapByRequest.size()>0) {
                    System.out.println("map[0]:" + mapByRequest.keySet().toArray()[0]);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            
    //        String requestString = ReadHttpRequest.getRequestInputStream(request);
    //        System.out.println("requestString:" + requestString);
    
            HtmlUtil.write(response, "success");
        }
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            HtmlUtil.write(response, "this is doGet()");
        }
    }
    View Code

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

    import javax.net.ssl.HttpsURLConnection;
    import java.io.*;
    import java.net.HttpURLConnection;
    import java.net.SocketTimeoutException;
    import java.net.URL;
    import java.util.Map;
    
    public class HttpUtil {
    
        /**
         * 发送http请求并接收返回,字符集默认UTF-8
         *
         * @param url         请求地址
         * @param sendData    发送数据
         * @param connTimeOut 连接超时
         * @param readTimeOut 响应超时
         * @return 返回报文
         * @throws Exception
         */
        public static String sendAndRcvHttpPost(String url, String sendData, int connTimeOut, int readTimeOut) {
            return sendAndRcvHttpPost(url, sendData, "UTF-8", connTimeOut, readTimeOut, "");
        }
    
        /**
         * 发送http请求并接收返回,(指定字符集)
         *
         * @param url         请求地址
         * @param sendData    发送数据
         * @param charset   字符集
         * @param connTimeOut 连接超时
         * @param readTimeOut 响应超时
         * @param lineSpliter 换行符
         * @return 返回报文
         * @throws Exception
         */
        public static String sendAndRcvHttpPost(String url, String sendData, String charset, int connTimeOut, int readTimeOut, String lineSpliter) {
            return sendAndRcvHttpPostBase(url, sendData, charset, connTimeOut, readTimeOut,
                    "application/x-www-form-urlencoded;charset=" + charset,
    //                "text/plain",
                    null, lineSpliter);
        }
    
        public static String sendAndRcvHttpPostBase(String url, String oriData, String charset, int connTimeOut, int readTimeOut,
                                                    String contentType, Map<String, String> header, String lineSpliter) {
            Long curTime = System.currentTimeMillis();
            String tag = "@" + curTime;
            String result = "";
            BufferedReader in = null;
            DataOutputStream out = null;
            int code = 999;
            HttpsURLConnection httpsConn = null;
            HttpURLConnection httpConn = null;
            InputStream httpin = null;
            try {
                byte[] sendData = oriData.getBytes(charset);
                tag = sendData.hashCode() + tag;
    //            Trace.logInfo(Trace.COMPONENT_HTTP, "SimpleHttpConnUtil Prepare:"+tag );
                URL myURL = new URL(url);
    //            Trace.logInfo(Trace.COMPONENT_HTTP, "请求地址:"+url);
    
                httpConn = (HttpURLConnection) myURL.openConnection();
                httpConn.setRequestProperty("Accept-Charset", charset);
                httpConn.setRequestProperty("user-agent", "Rich Powered/1.0");
                if (header != null) {
                    for (String key : header.keySet()) {
                        httpConn.setRequestProperty(key, (String) header.get(key));
                    }
                }
                httpConn.setRequestMethod("POST");
                httpConn.setUseCaches(false);
                httpConn.setRequestProperty("Content-Type", contentType);
                httpConn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;");
    //                httpConn.setRequestProperty("Accept-Encoding","gzip, deflate, sdch");
                httpConn.setRequestProperty("Accept-Language", "zh-CN,zh;");
                httpConn.setRequestProperty("Cache-Control", "no-cache");
                httpConn.setRequestProperty("Pragma", "no-cache");
                httpConn.setRequestProperty("Content-Length", sendData.length + "");
                httpConn.setConnectTimeout(connTimeOut);
                httpConn.setReadTimeout(readTimeOut);
                httpConn.setDoInput(true);
                httpConn.setInstanceFollowRedirects(true);
                if (sendData != null) {
                    httpConn.setDoOutput(true);
                    // 获取URLConnection对象对应的输出流
                    try {
                        httpConn.connect();
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                    out = new DataOutputStream(httpConn.getOutputStream());
                    // 发送请求参数
                    out.write(sendData);
                    // flush输出流的缓冲
                    out.flush();
                    out.close();
                }
                // 取得该连接的输入流,以读取响应内容
                code = httpConn.getResponseCode();
                httpin = httpConn.getInputStream();
    
                if (HttpURLConnection.HTTP_OK == code) {
                    String line;
    
                    in = new BufferedReader(new InputStreamReader(httpin, charset));
                    while ((line = in.readLine()) != null) {
                        result += line + lineSpliter;
                    }
                } else {
                    result = null;
                    throw new Exception("支付失败,服务端响应码:" + code);
                }
            } catch (SocketTimeoutException e) {
    //            Trace.logError(Trace.COMPONENT_ACTION, "获取返回报文超时!",e);
                result = "TO";
            } catch (Exception e) {
    //            Trace.logError(Trace.COMPONENT_ACTION, "http通讯失败 !",e);
                result = null;
            } finally {
    //            Trace.logInfo(Trace.COMPONENT_ACTION,"对方地址:"+url);
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                    }
                }
                if (httpConn != null) {
                    httpConn.disconnect();
                }
                if (httpsConn != null) {
                    httpsConn.disconnect();
                }
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                    }
                }
            }
    //        Trace.logInfo(Trace.COMPONENT_HTTP, "SimpleHttpConnUtil "+tag+" end for "+(System.currentTimeMillis()-curTime)+"ms");
            return result;
        }
    
    }
    View Code

    客户端测试方法:

    public class TestMain {
        public static void main(String[] args) {
    //        String reqData ="p1=a&p2=b&p3=c";
            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"}";
            String reqUrl = "http://localhost:8080/test_tomcat_web_war_exploded/form03_6_2_Token_OpenCard_Back";
    //        String reqUrl="http://localhost:8083/H5api/xx";
            String result = HttpUtil.sendAndRcvHttpPost(reqUrl, reqData, 100000, 1000000);
            System.out.println(result);
        }
    }


    【测试结论】

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

    六月 11, 2019 10:11:53 上午 org.apache.tomcat.util.http.Parameters processParameters
    信息: 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.
    Note: further occurrences of Parameter errors will be logged at DEBUG level.
    
    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流的代码:

    package com;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.*;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    public class ReadHttpRequest {
    
        /**
         * 从request.ParameterMap获取数据---适用于表单请求
         * @param request
         * @return
         * @throws UnsupportedEncodingException
         * @throws Exception
         */
        public static Map getRequestMap(HttpServletRequest request) throws UnsupportedEncodingException,Exception {
            Map result = new HashMap();
            Map<String, String[]> map = request.getParameterMap();
            if (0 == map.size()) {
                System.out.println("未获取到任何请求参数.");
    //            throw new  Exception("未获取到任何请求参数.");
                return result;
            }
    
            for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
                Map.Entry element = (Map.Entry) iter.next();
                Object strKey = element.getKey();  //key值
                String[] value = (String[]) element.getValue(); //value,数组形式
                String values = "";
                for (int i = 0; i < value.length; i++) {
                    values += "," + value[i];
                }
                result.put(strKey.toString(), values.replaceFirst(",", ""));
            }
            return result;
        }
    
    
        /**
         * 从输入流获取数据---适用于流请求
         * @param request
         * @return
         */
        public static String getRequestInputStream(HttpServletRequest request) {
            InputStream in = null;
            ByteArrayOutputStream out = null;
            try {
                in = request.getInputStream();
                out = new ByteArrayOutputStream();
                in2OutStream(in, out, 1024 * 1024);
                return out.toString("UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (out != null) out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (in != null) in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
        private static void in2OutStream(InputStream in, OutputStream out,
                                         int bufferSize) throws IOException {
            byte[] buffer = new byte[bufferSize];// 缓冲区
            for (int bytesRead = 0; (bytesRead = in.read(buffer)) != -1; ) {
                out.write(buffer, 0, bytesRead);
                Arrays.fill(buffer, (byte) 0);
            }
        }
    }
    View Code

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

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

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

  • 相关阅读:
    Spring Cloud云架构
    Spring Cloud云架构
    Spring Cloud云架构
    Spring Cloud云架构
    Spring Cloud Consul
    Spring Cloud Eureka
    构建Spring Cloud微服务分布式云架构
    数据库三范式
    redis3.0.0 集群安装详细步骤
    sql优化的几种方法
  • 原文地址:https://www.cnblogs.com/buguge/p/11002836.html
Copyright © 2011-2022 走看看