一个因为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,只有慢慢分析代码打日志排查了!