tomcat與jetty接收請求參數的區別 tomcat與jetty接收請求參數的區別 比較兩種方式的form請求提交 Post方式的Http流請求調用

【場景】

服務端點對點通知。
A服務發起請求B服務,B同步返回接收成功;而後B開始處理邏輯;B處理完成後異步通知給A;A接收請求並處理,同步回寫響應給B;完成。html

【先上代碼】

服務端(接收端)代碼: java

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工具類:web

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

 

客戶端測試方法:apache

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的日誌:json

六月 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]。api

個人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處理字符編碼的問題。tomcat

 

【話說回來】

話說回來,上面案例content-type用form實在不合適不地道,由於想獲取到請求數據,得取key的值而不是value,這不符合經常使用的套路啊,由此個人同事那天在接收數據時很折騰了一番。像這種上送json字符串的,改用text/plain更合適,這樣的話,接收端經過讀取HttpServletRequest的輸入流就能夠獲取到請求數據。app


附上讀取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流請求調用

相關文章
相關標籤/搜索