本节摘要:采用httpclient插件的post方式发送二进制数据流到http服务端
说明,本节在我之前的一篇博客get/post方式调用http接口的基础上来介绍,本节的代码和之前的这篇博客放在同一个工程目录的同一个包下。
1.背景介绍
最近项目中发布了一个HTTP服务,HTTP服务端采用二进制流来接收数据,
与其他系统的同事联调的时候,总是出现一些问题,现把这些问题列出来,并在代码中得到了解决。
(1)请求的中文,服务器端接收到后为乱码
(2)客户端接收到服务器端的响应报文后,中文为乱码
(3)请求的报文中没有设置字符集,服务器报空指针异常
(4)客户端发送请求后,服务器端接收到的二进制数据的长度为0,报NegativeArraySizeExceptio异常
(5)服务端接收到客户端的报文后里面全是百分号以及英文字母(不用说,你懂的。)
之前介绍过采用JDK自带的java.net.HttpURLConnection(见博客get/post发送HTTP请求2)可以解决这个问题,但是项目中发现客户端很多同事都是采用的httpclient插件,那咱这次就用httpclient插件来发送post请求,并解决以上问题。服务端接收代码以及输出代码不能改,那么我们只能想千方设百计的去修改完善我们客户端的代码。
2.代码如下:
之前的博客get/post方式调用http接口,这个直接采用发送字符串的形式,也没有解决中文问题,
废话咱就不多说了,直接上代码
(1)修改web.xml配置文件,增加以下几行

1 <!-- 模拟HTTP的调用,写的一个只处理POST请求的http服务 --> 2 <servlet> 3 <servlet-name>PostHttpServer</servlet-name> 4 <servlet-class>httpcall.PostHttpServer</servlet-class> 5 </servlet> 6 7 <servlet-mapping> 8 <servlet-name>PostHttpServer</servlet-name> 9 <url-pattern>/postHttpServer</url-pattern> 10 </servlet-mapping>
servlet的配置,很easy
(2)HTTP服务器端的代码

1 package httpcall; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 /** 11 * 12 *Module: PostHttpServer.java 13 *Description: 模拟的一个Http服务,处理客户端的post请求 14 *Company: 15 *Author: pantp 16 *Date: May 5, 2012 17 */ 18 public class PostHttpServer extends HttpServlet { 19 20 private static final long serialVersionUID = 1L; 21 22 /* 23 * 代码逻辑分以下三部分: 24 * 1.获得请求报文 25 * 2.根据请求报文的信息去做业务逻辑,然后封装返回报文 26 * 3.输出相应报文 27 */ 28 protected void doPost(HttpServletRequest request, 29 HttpServletResponse response) throws ServletException, IOException { 30 String inJson = null;// 保存HTTP客户端请求报文 31 String outJson = null;// 保存HTTP服务端输出报文 32 33 // 获得输人报文然后打印出来 34 inJson = getInJson(request); 35 System.out 36 .println("\nauthor<pantp>===========服务端日志----POST方式接收HTTP请求,HTTP服务端收到的请求报文如下:==========\n"); 37 System.out.println(inJson); 38 System.out 39 .println("\nauthor<pantp>=================================================================\n"); 40 41 // 以下代码部分获得请求报文,然后去做校验,转换以及其他的调用其他的业务逻辑等,这里就不管它 42 // ........................................................................ 43 44 // 下面部分是输出部分的处理 45 outJson = "{\"Response\": {\"code\": \"0\",\"message\": \"成功\",\"data\": \"12345\"}}";// 输出不部分也以JSON格式的字符串输出,这里我就写死 46 47 response.setContentType("application/json; charset=UTF-8"); 48 response.getWriter().print(outJson); 49 } 50 51 // 获得请求的报文,并作简单的校验 52 public String getInJson(HttpServletRequest request) throws IOException { 53 54 byte buffer[] = new byte[64 * 1024]; 55 InputStream in = request.getInputStream();// 获取输入流对象 56 57 int len = in.read(buffer); 58 // 必须对数组长度进行判断,否则在new byte[len]会报NegativeArraySizeException异常 59 if (len < 0) { 60 throw new IOException("请求报文为空"); 61 } 62 63 String encode = request.getCharacterEncoding();// 获取请求头编码 64 // 必须对编码进行校验,否则在new String(data, encode);会报空指针异常 65 if (null == encode || encode.trim().length() < 0) { 66 throw new IOException("请求报文未指明请求编码"); 67 } 68 69 byte data[] = new byte[len]; 70 71 // 把buffer数组的值复制到data数组 72 System.arraycopy(buffer, 0, data, 0, len); 73 74 // 通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String 75 String inJson = new String(data, encode); 76 77 return inJson; 78 } 79 80 // 不提供get的处理方式 81 protected void doGet(HttpServletRequest request, HttpServletResponse response) 82 throws ServletException, IOException { 83 } 84 }
(3)HTTP客户端的代码

1 package httpcall; 2 3 import java.io.IOException; 4 import org.apache.commons.httpclient.HttpClient; 5 import org.apache.commons.httpclient.HttpException; 6 import org.apache.commons.httpclient.HttpStatus; 7 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; 8 import org.apache.commons.httpclient.methods.EntityEnclosingMethod; 9 import org.apache.commons.httpclient.methods.PostMethod; 10 import org.apache.commons.httpclient.methods.RequestEntity; 11 12 /** 13 * 14 *Module: PostHttpClient.java 15 *Description: 采用httpclient插件的post方式发送流二进制流数据到HTTP服务端 16 *Company: 17 *Author: pantp 18 *Date: May 5, 2012 19 */ 20 public class PostHttpClient { 21 22 /** 23 * 发送post请求,客户端采用二进制流发送,服务端采用二进制流介绍 24 * @param json 入参的json格式的报文 25 * @param url http服务器的地址 26 * @return 返回响应信息 27 */ 28 public static String postHttpReq(String json,String url) { 29 HttpClient httpClient = new HttpClient(); 30 31 byte b[] = json.getBytes();//把字符串转换为二进制数据 32 RequestEntity requestEntity = new ByteArrayRequestEntity(b); 33 34 EntityEnclosingMethod postMethod = new PostMethod(); 35 postMethod.setRequestEntity(requestEntity);// 设置数据 36 postMethod.setPath(url);// 设置服务的url 37 postMethod.setRequestHeader("Content-Type", "text/html;charset=GBK");// 设置请求头编码 38 39 // 设置连接超时 40 httpClient.getHttpConnectionManager().getParams().setConnectionTimeout( 41 5 * 1000); 42 // 设置读取超时 43 httpClient.getHttpConnectionManager().getParams().setSoTimeout(20 * 1000); 44 45 String responseMsg = ""; 46 int statusCode = 0; 47 try { 48 statusCode = httpClient.executeMethod(postMethod);// 发送请求 49 responseMsg = postMethod.getResponseBodyAsString();// 获取返回值 50 } catch (HttpException e) { 51 e.printStackTrace(); 52 } catch (IOException e) { 53 e.printStackTrace(); 54 } finally { 55 postMethod.releaseConnection();// 释放连接 56 } 57 58 if (statusCode != HttpStatus.SC_OK) { 59 System.out.println("HTTP服务异常" + statusCode); 60 } 61 return responseMsg; 62 } 63 64 //POST方式发送HTTP请求 65 public static void main(String[] args) { 66 String json = "{\"PubInfo\": {\"clinet\": \"10.70.128.132\",\"company\": \"月月鸟0820\"},\"Request\": {\"strBillId\": \"18221075148\",\"strCcsOpId\": \"1234\"}}"; 67 String url = "http://localhost:8080/UpDown/postHttpServer"; 68 String outPackage = null; 69 outPackage = postHttpReq(json, url); 70 System.out.println("客户端日志----POST方式调用HTTP,请求报文为:" + json); 71 System.out 72 .println("\nauthor<pantp>===========客户端日志----POST方式调用HTTP服务,HTTP服务端响应报文如下:=============\n"); 73 74 System.out.println(outPackage); 75 76 System.out 77 .println("\nauthor<pantp>================================================================\n"); 78 } 79 80 }
3.测试结果
部署项目,启动tomc,运行客户端代码中的main方式
客户端的测试结果如下:
服务端的测试结果如下: