一直习惯于spring boot傻瓜式操作的我这几天被要求维护一个别说spring mvc,连spring都没有应用的原生项目。并要在其中调用一个第三方接口。
本来以为没多大问题,所以直接搜索了HttpClient的post。
但是实际应用起来一直报错:
org.apache.http.ConnectionClosedException: Premature end of chunk coded message body: closing chunk expected
我大致百度了一下什么流先关闭,所以最后接收response的时候未读取完,或者等等类似,反正不单纯只是这块代码的问题。其实仔细找应该可能也能找到,但是原谅我知识浅薄还爱偷懒。实在不想在原项目代码多出debug。所以灵机一动换一种调用第三方接口的方式。
最原始的方式,流的开启关闭自己控制,总不会再报错了吧?结果试了以后果然可以,所以在此贴出,以便于记忆查找,如果能帮助到别人更好不过了。
首先,这个分为两步,因为是post,所以参数拼接并不能像get一样直接拼,我这里是封装好了一个方法来专门拼接参数的。第二 步才是发送post请求。
原生发送post请求:
// 拼接参数
public static String createLinkString(HashMap<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
StringBuilder prestrSB = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {
prestrSB.append(key).append("=").append(value);
} else {
prestrSB.append(key).append("=").append(value).append("&");
}
}
return prestrSB.toString();
}
// POST
public static String sendPost(String url, String param) {
OutputStreamWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
HttpURLConnection conn = null;
conn = (HttpURLConnection) realUrl.openConnection();
// 打开和URL之间的连接
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST"); // POST方法
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
conn.connect();
// 获取URLConnection对象对应的输出流
out = new OutputStreamWriter(conn.getOutputStream(),"UTF-8");
// 发送请求参数
out.write(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
至此,一个原始但可靠的post请求的接口就写好了。
不过我还是多有不忿,因为我以前没有restTemplate的时候httpClient也是用过的啊,所以刚刚做了个小demo成功通过测试并在此贴出,以防以后需要用到。
httpClient发送post请求:
public static String sendPost(String url){
//先把参数转化成json
JSONObject params = new JSONObject();
json.element("参数名", 参数值);
json.element("userName", userName);
//创建client
HttpClient client = HttpClients.createDefault();
//创建一个post对象
HttpPost post = new HttpPost(url);
post.setHeader("Connection", "close");
try {
StringEntity s = new StringEntity(jsonParam.toString(), "UTF-8");
s.setContentType("application/json");
post.setEntity(s);
HttpResponse res = client.execute(post);
HttpEntity entity = res.getEntity();
String result = EntityUtils.toString(entity);
return result;
} catch (Exception e) {
throw e;
}
}
就这么简单的post发送成功了!(我是在一个main方法里跑的。)然后我最开始就遇到的那个问题至今还没找原因,毕竟项目有点大,耐心有点少,问题不太好找。
restTemplate发送post请求
最后的最后还是要安利一下我spring封装好的restTemplate。
其实说真的,最近有个小发现(不确定是不是我个人错觉),就是一个没有用spring框架的不算小的项目,启动的飞快。然后用了spring boot框架,东西不多的项目启动都比刚刚说的那个原生项目慢得多。
不过我不介意啊,好用就行。继续说restTemplate:
首先依赖注入:
![](https://img.haomeiwen.com/i16553345/f12bccd45fc5ded8.png)
![](https://img.haomeiwen.com/i16553345/ef8df185d9b17adc.png)
然后可以开始正常使用了,因为被spring整合了,所以不用引入什么包
// 访问服务器接口
String url = "http://" + serverIp + "/sys-tms/tms/getAllCarList";
//添加参数
MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
paramMap.add("company", company);
// 获取返回结果
ResponseEntity<String> result = restTemplate.postForEntity(url, paramMap, String.class);
// 如果状态等于200则证明查询成功。否则接口调用失败
if (result.getStatusCodeValue() == 200) {
String result =result.getBody();
}
至此结束。
顺便说一下,这三种方法我都是实际测试过的,restTemplate和第一个种原生方式都在正式使用,中间的httpclient也是测试通过了的。如果你复制粘贴有什么问题大部分可能是哪里没改对或者版本什么的区别。
最后,全文手打这么不容易的写个文如果你觉得用到了,留个言点个赞转个发什么的啊~
顺便再说个挺暖心的事,前一段时间用到内网穿透看到一个技术贴不错,并且楼主留下了邮箱说不会的可以邮件问,当时因为有一些疑惑所以发了邮件,结果昨天收到了回复。虽然时间久点,问题已经解决了,但是起码收到回复就是一件很开心的事情啊!很喜欢这种氛围。予人玫瑰,手有余香。
网友评论