本篇记录一个bug出现与解决的过程,希望以后在了解了更多的技术细节的基础上,可以对现阶段的一些代码块进行进一步改进。
在接触到的第一个项目中,使用了一个同事写的HttpUtil,其中的get请求:
public static String getMethod(String url) { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet get = new HttpGet(url); get.addHeader("Content-Type", "application/json; charset=utf-8"); CloseableHttpResponse response = null; try { response = httpclient.execute(get); String rev = EntityUtils.toString(response.getEntity()); return rev; } catch (Exception e) { log.info(e.getMessage());return null; } finally { get.releaseConnection(); close(httpclient, response); } }
但是当响应中出现中文时,该方法的返回值会有乱码,于是有了第二版,他将返回的内容用输入流接收,并规定编码格式(其实我在想用toString(HttpEntity,Charset)会不会有效果,没试过):
/** * httpGET请求,中文不乱码 * * @param url * @return */ public static String httpByGet(String url) { StringBuffer response = new StringBuffer(); HttpClient client = new HttpClient(); HttpMethod method = new GetMethod(url); BufferedReader reader = null; InputStreamReader in = null; InputStream input = null; try { client.executeMethod(method); if (method.getStatusCode() == HttpStatus.SC_OK) { input = method.getResponseBodyAsStream(); in = new InputStreamReader(input, "UTF-8"); if (in != null) { reader = new BufferedReader(in); String line; while ((line = reader.readLine()) != null) { response.append(line); } } } } catch (Exception e) { log.info(e.getMessage()); } finally { try { if (input != null) { input.close(); } if (in != null) { in.close(); } if (reader != null) { reader.close(); } } catch (IOException ex) { log.info(e.getMessage()); } } return response.toString(); }
这个方法解决了中文乱码的问题,之后一直在项目中使用该方法,但不久又出现了另一个问题。当时需要传入多个参数才能调用另一个接口,一般来说,参数太多的情况还是会倾向用post方法,一来url的长度有限制,二来在请求体中处理一些特殊符号也更容易,但是那个接口只有get方法才能请求,所以在调用这个方法时,还是得拼接url。很快url拼接成功,但是由于value中大量特殊符号不得不采用URLEncoder对其进行转义,转义之后请求发送成功。这个时候,使用接口的同事发现,虽然采用该方法可以成功取到返回的内容,但与在浏览器中返回的内容不一致。
但是既然浏览器可以成功返回指定的内容,那就可以按照浏览器访问的模式去发送请求,于是利用postman成功发送一条请求,并且用了它的generate code工具(postman也是个神器,我觉得要系统学习一下这个工具,应该可以为开发省事不少),找到了它用java实现的代码(OKHttpClient),但还是采用了拼接URL的方式,将请求发送出去,得到返回结果。
public static String httpByOKGet(String url) { OkHttpClient client = new OkHttpClient(); client.setReadTimeout(60, TimeUnit.SECONDS); client.setWriteTimeout(60, TimeUnit.SECONDS); client.setConnectTimeout(60, TimeUnit.SECONDS); Request request = new Request.Builder().url(url).get().addHeader("content-type", "application/json") .addHeader("cache-control", "no-cache") .addHeader("postman-token", "c155bbab-f11c-7fa3-b155-e69906f67d75").build(); StringBuilder sb = new StringBuilder(); InputStream input = null; InputStreamReader in = null; BufferedReader reader = null; try { Response response = client.newCall(request).execute(); input = response.body().byteStream(); in = new InputStreamReader(input, "UTF-8"); if (in != null) { reader = new BufferedReader(in); String line; while ((line = reader.readLine()) != null) { sb.append(line); } } } catch (IOException e) { e.printStackTrace(); } finally { try { if (input != null) { input.close(); } if (in != null) { in.close(); } if (reader != null) { reader.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return sb.toString(); }
应急还可以,只是每次这个url就这么拼接总觉得不妥,而且当时居然就直接把postman的token带在里面写到了util包的类里...后期用了BasicNameValuePair来处理这些参数,觉得规范了一些,但是httpClient这一块儿还是不系统,后期就专门在这一小块儿上看看文档,总结最新版的常见用法,归纳到博客中。