一个因为URLEncoder和URLDecoder引发的bug

引言

      最近公司项目遇到项目之间的项目调用,通过HttpURLConnection实现的,不过在此过程中,遇到了中文和特殊字符的问题,结果最后排查半天是因为中文和特殊字符(%)导致的接口调不通或是调通接口后,解析数据出现异常,问题很隐蔽难排查,不过好在最后还是功夫不负有心人,只是耽误了点时间!

1:调用URL中出现中文参数的问题

//删除VBD-IIS大数据违法记录
    public boolean delVehicleBigData(String  vehicleBigDataUrl,String plateNo,String passTime){
        boolean flag=false;
        StringBuffer strURLCount = new StringBuffer();
//vehicleBigDataUrl请求路径 如:http://10.30.27.153:8090 strURLCount.append(vehicleBigDataUrl
+ "/VBD/illegal/deleteIllegalData?"); try { strURLCount.append("plateNo="+URLEncoder.encode(plateNo,"utf-8")); //鄂AK7259 strURLCount.append("&passTime="+URLEncoder.encode(passTime,"utf-8")); JSONObject jsonObject = Tools.insert(strURLCount.toString()); if(jsonObject.isNullObject()){ LogUtil.error("jsonObject = null"); flag=false; } int ret = jsonObject.getInt("ret"); if(0 != ret){ LogUtil.error("ret = " + ret); flag=true; }else{ flag=false; } }catch(UnsupportedEncodingException e1) { e1.printStackTrace(); } return flag; }

Tools帮助类

     /**
     * 方法说明: 调用URL返回结果
     *
     * @param Url
     * @return 
     * @作者及日期:zhaosqing    2020-09-21
     * @修改人及日期:zhaosqing  2020-09-21
     * @修改描述:
     * @其他:
     */
    public static JSONObject insert(String Url){
        if(null == Url){
            return null;
        }
        StringBuffer strBuffer = new StringBuffer();
        BufferedReader brd =null;
        HttpURLConnection connet = null;
        try {
            URL url = new URL(Url);
              //实例一个HTTP CONNECT
              connet = (HttpURLConnection) url.openConnection();
              connet.setRequestMethod("GET");
              connet.setDoOutput(true);
              connet.setDoInput(true);
              connet.setUseCaches(false);
              connet.setConnectTimeout(300000);
              connet.setReadTimeout(300000);
              connet.connect();
              if(connet.getResponseCode() != 200){
                  throw new IOException(connet.getResponseMessage());
              }
              //将返回的值存入到String中
              brd = new BufferedReader(new InputStreamReader(connet.getInputStream(),"utf8"));
              String line=brd.readLine();
              while(line != null){
                  line = java.net.URLDecoder.decode(line, "UTF-8");
                  strBuffer.append(line);
                  line = brd.readLine();
              }
        } catch (MalformedURLException e) {
                LogUtil.error("insert MalformedURLException:" + e.getMessage());
            return null;
        } catch (IOException e) {
                LogUtil.error("insert IOException:" + e.getMessage());
            return null;
        }finally{
            if(brd !=null){
                 try {
                     brd.close();
                 } catch (IOException e) {
                 }
            }
            if(connet!=null){
                connet.disconnect();
            }
        }
        return JSONObject.fromObject(strBuffer.toString());
    }

因为调用URL的里边包含车牌号plateNo和同行时间passTime,车牌号必要会带中文参数的,如鄂AK7259,这就会导致调用http请求的时候,请求失败,只有先将plateNo通过URLEncoder.encode(plateNo,"utf-8"))编码后,然后再拼接到url中,最后接收请求的时候,在通过解码的方式,将其还原成中文,如:String plaeteNo= URLDecoder.decode(illegal .getPlateNo(),"utf-8"); 

2:调用URL返回结果中包含特殊字符如(%)

    /**
     * 获取大数据违法类型列表
     * @param vehicleBigDataUrl
     * @return
     * @throws Exception 
     */
    public List<ItsCodewfdm> getAllwfdmCodeList() throws Exception{
        List<ItsCodewfdm> list=new ArrayList<ItsCodewfdm>();
        String vehicleBigDataUrl=this.vehicleBigDataUrl();//获取大数据服务器的ip和端口
        StringBuffer strURLCount = new StringBuffer();
         try {
//vehicleBigDataUrl 请求的url 如 http://10.30.27.153:8090 strURLCount.append(vehicleBigDataUrl
+ "/VBD/illegal/queryAllwfdmCodeList"); JSONObject jsonObject = Tools.getWfdmCodeListByVBD(strURLCount.toString()); if(jsonObject.isNullObject()){ LogUtil.error("jsonObject = null"); return list; } String content=jsonObject.getString("content"); JSONArray array= JSONArray.fromObject(content); if(array!=null && array.size()>0){ for(int i=0;i<array.size();i++){ ItsCodewfdm wfdm =new ItsCodewfdm(); wfdm.setDm(array.getJSONObject(i).getString("dm")); wfdm.setWfxw(array.getJSONObject(i).getString("wfxw")); list.add(wfdm); } } } catch (Exception e) { e.printStackTrace(); } return list; }

 Tools帮助类

/**
     * 方法说明: 调用URL返回结果
     * 返回vbd违法类型数据
     * @param Url
     * @return 
     * @作者及日期:zhaosqing    2020-09-20
     * @修改描述:
     * @其他:
     */
    public static JSONObject getWfdmCodeListByVBD(String Url){
        if(null == Url){
            return null;
        }
        StringBuffer strBuffer = new StringBuffer();
        BufferedReader brd =null;
        HttpURLConnection connet = null;
        try {
            URL url = new URL(Url);
              //实例一个HTTP CONNECT
              connet = (HttpURLConnection) url.openConnection();
              connet.setRequestMethod("GET");
              connet.setDoOutput(true);
              connet.setDoInput(true);
              connet.setUseCaches(false);
              connet.setConnectTimeout(300000);
              connet.setReadTimeout(300000);
              connet.connect();
              if(connet.getResponseCode() != 200){
                  throw new IOException(connet.getResponseMessage());
              }
              //将返回的值存入到String中
              brd = new BufferedReader(new InputStreamReader(connet.getInputStream(),"utf8"));
              String line=brd.readLine();
              //处理返回结果中包含%的问题 (如:超速20%-50%)
              if(line.contains("%")){
                  line=URLEncoder.encode(line,"UTF-8");
              }
              while(line != null){
                  line = java.net.URLDecoder.decode(line, "UTF-8");
                  strBuffer.append(line);
                  line = brd.readLine();
              }
        } catch (MalformedURLException e) {
                LogUtil.error("insert MalformedURLException:" + e.getMessage());
            return null;
        } catch (IOException e) {
                LogUtil.error("insert IOException:" + e.getMessage());
            return null;
        }finally{
            if(brd !=null){
                 try {
                     brd.close();
                 } catch (IOException e) {
                 }
            }
            if(connet!=null){
                connet.disconnect();
            }
        }
        return JSONObject.fromObject(strBuffer.toString());
    }

因为请求url后通过IO流的方式获取查询到的结果然后解析,在返回的line结果中包含特殊字符,然后通过URLDecoder.decode(line, "UTF-8");进行解码后就出现异常了,所以得判断一下,时候包含特殊字符,如果包含就先将其URLEncoder.encode(line,"UTF-8");编码再解码就不会出现问题。

至此,问题排查分析完了,不过在当初项目中你排查的时候,可是费了一番功夫排查的,因为项目部署在服务器Linux系统上,不能远程debug,只有慢慢分析代码打日志排查了!

原文地址:https://www.cnblogs.com/zhaosq/p/13723428.html