在写网络程序的时候,经常会有从网址获取数据的需求,上一篇解析JSON就需要从百度获取天气数据,本文介绍一种Java发送http请求的工具–HttpClient。
##HttpClient的介绍
The most essential function of HttpClient is to execute HTTP methods. Execution of an HTTP method involves one or several HTTP request / HTTP response exchanges, usually handled internally by HttpClient. The user is expected to provide a request object to execute and HttpClient is expected to transmit the request to the target server return a corresponding response object, or throw an exception if execution was unsuccessful.
HttpClient最基本的功能就是执行http方法,执行http方法包括了一次或者几次HTTP请求和相应的变化,通常也是通过HttpClient来处理的。只要用户提供一个request的对象,HttpClient就会将用户的请求发送到目标服务器上,并且返回一个respone对象,如果没有执行成功将抛出一个异常。
通过文档的介绍我们可以知道,发送HTTP请求一般可以分为以下步骤
- 取得HttpClient对象
- 封装http请求
- 执行http请求
- 处理结果
其中可以发送的请求类型有GET, HEAD, POST, PUT, DELETE, TRACE 和 OPTIONS
HttpClient supports out of the box all HTTP methods defined in the HTTP/1.1 specification: GET, HEAD, POST, PUT, DELETE, TRACE and OPTIONS.
官方文档中的示例
//1.获得一个httpclient对象CloseableHttpClient httpclient =HttpClients.createDefault();//2.生成一个get请求HttpGet httpget =newHttpGet("http://localhost/");//3.执行get请求并返回结果CloseableHttpResponse response =httpclient.execute(httpget);try{ //4.处理结果}finally{ response.close();}
介绍一下最常用的HttpGet和HttpPost。
RESTful提倡,通过HTTP请求对应的POST、GET、PUT、DELETE来完成对应的CRUD操作。
所以本文介绍一下通过GET获取数据和POST提交数据的实现方法。
##发送HttpGet
先介绍发送HttpGet请求
/** * 发送HttpGet请求 * @param url * @return */ publicstaticString sendGet(String url){ //1.获得一个httpclient对象 CloseableHttpClient httpclient =HttpClients.createDefault(); //2.生成一个get请求 HttpGet httpget =newHttpGet(url); CloseableHttpResponse response =null; try{ //3.执行get请求并返回结果 response =httpclient.execute(httpget); }catch(IOExceptione1){ e1.printStackTrace(); } String result =null; try{ //4.处理结果,这里将结果返回为字符串 HttpEntity entity =response.getEntity(); if(entity !=null){ result =EntityUtils.toString(entity); } }catch(ParseException|IOException e){ e.printStackTrace(); }finally{ try{ response.close(); }catch(IOExceptione){ e.printStackTrace(); } } returnresult; }
##发送HttpPost
发送HttpPost的方法和发送HttpGet很类似,只是将请求类型给位HttpPost即可。
代码如下
/** * 发送不带参数的HttpPost请求 * @param url * @return */ publicstaticString sendPost(String url){ //1.获得一个httpclient对象 CloseableHttpClient httpclient =HttpClients.createDefault(); //2.生成一个post请求 HttpPost httppost =newHttpPost(url); CloseableHttpResponse response =null; try{ //3.执行get请求并返回结果 response =httpclient.execute(httppost); }catch(IOExceptione){ e.printStackTrace(); } //4.处理结果,这里将结果返回为字符串 HttpEntity entity =response.getEntity(); String result =null; try{ result =EntityUtils.toString(entity); }catch(ParseException|IOException e){ e.printStackTrace(); } returnresult; }
##带参数的HttpPost
发送带参数的HttpPost
Many applications need to simulate the process of submitting an HTML form, for instance, in order to log in to a web application or submit input data. HttpClient provides the entity class UrlEncodedFormEntity to facilitate the process.
HttpClient通过UrlEncodedFormEntity,来提交带参数的请求
将需要提交的参数放在map里
代码如下
/** * 发送HttpPost请求,参数为map * @param url * @param map * @return */ publicstaticString sendPost(String url,Map<String, String>map){ CloseableHttpClient httpclient =HttpClients.createDefault(); List<NameValuePair>formparams =newArrayList<NameValuePair>(); for(Map.Entry<String, String>entry :map.entrySet()){ //给参数赋值 formparams.add(newBasicNameValuePair(entry.getKey(),entry.getValue())); } UrlEncodedFormEntity entity =newUrlEncodedFormEntity(formparams,Consts.UTF_8); HttpPost httppost =newHttpPost(url); httppost.setEntity(entity); CloseableHttpResponse response =null; try{ response =httpclient.execute(httppost); }catch(IOExceptione){ e.printStackTrace(); } HttpEntity entity1 =response.getEntity(); String result =null; try{ result =EntityUtils.toString(entity1); }catch(ParseException|IOException e){ e.printStackTrace(); } returnresult; }
##完整代码
完成代码如下,用到的jar包有httpclient-4.5.1.jar,httpcore-4.4.3.jar,依赖的jar有commons-logging-1.2.jar
注意是Apache HttpClient,不是commons-httpclient
importjava.io.IOException;importjava.util.ArrayList;importjava.util.List;importjava.util.Map;importorg.apache.http.Consts;importorg.apache.http.HttpEntity;importorg.apache.http.NameValuePair;importorg.apache.http.ParseException;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpGet;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.apache.http.message.BasicNameValuePair;importorg.apache.http.util.EntityUtils;/** * @author GWCheng * */publicclassHttpUtil{ privatestaticfinalCloseableHttpClient httpclient =HttpClients.createDefault(); /** * 发送HttpGet请求 * @param url * @return */ publicstaticString sendGet(String url){ HttpGet httpget =newHttpGet(url); CloseableHttpResponse response =null; try{ response =httpclient.execute(httpget); }catch(IOExceptione1){ e1.printStackTrace(); } String result =null; try{ HttpEntity entity =response.getEntity(); if(entity !=null){ result =EntityUtils.toString(entity); } }catch(ParseException|IOException e){ e.printStackTrace(); }finally{ try{ response.close(); }catch(IOExceptione){ e.printStackTrace(); } } returnresult; } /** * 发送HttpPost请求,参数为map * @param url * @param map * @return */ publicstaticString sendPost(String url,Map<String, String>map){ List<NameValuePair>formparams =newArrayList<NameValuePair>(); for(Map.Entry<String, String>entry :map.entrySet()){ formparams.add(newBasicNameValuePair(entry.getKey(),entry.getValue())); } UrlEncodedFormEntity entity =newUrlEncodedFormEntity(formparams,Consts.UTF_8); HttpPost httppost =newHttpPost(url); httppost.setEntity(entity); CloseableHttpResponse response =null; try{ response =httpclient.execute(httppost); }catch(IOExceptione){ e.printStackTrace(); } HttpEntity entity1 =response.getEntity(); String result =null; try{ result =EntityUtils.toString(entity1); }catch(ParseException|IOException e){ e.printStackTrace(); } returnresult; } /** * 发送不带参数的HttpPost请求 * @param url * @return */ publicstaticString sendPost(String url){ HttpPost httppost =newHttpPost(url); CloseableHttpResponse response =null; try{ response =httpclient.execute(httppost); }catch(IOExceptione){ e.printStackTrace(); } HttpEntity entity =response.getEntity(); String result =null; try{ result =EntityUtils.toString(entity); }catch(ParseException|IOException e){ e.printStackTrace(); } returnresult; }}
##测试用例
服务器端代码
@Controller@RequestMapping("/test")// /test/**publicclassTestController{ // /test/view post 提交数据,模拟表单 @RequestMapping(value ="/view",method =RequestMethod.POST) publicvoidviewTest(PrintWriter out,HttpServletResponse response,@RequestParam("param1")String param1, @RequestParam("param2")String param2){ response.setContentType("application/json;charset=UTF-8"); Gson gson =newGsonBuilder().create(); Map<String, Object>map =newHashMap<String, Object>(); map.put("param1",param1); map.put("param2",param2); System.out.println(gson.toJson(map)); out.print(gson.toJson(map)); } // /test/view?param1=aaa¶m2=bbb get @RequestMapping(value ="/view",method =RequestMethod.GET) publicvoidviewTest3(PrintWriter out,HttpServletResponse response,@RequestParam("param1")String param1, @RequestParam("param2")String param2){ response.setContentType("application/json;charset=UTF-8"); Gson gson =newGsonBuilder().create(); Map<String, Object>map =newHashMap<String, Object>(); map.put("param1",param1); map.put("param2",param2); System.out.println(gson.toJson(map)); out.print(gson.toJson(map)); } // /test/view2/{courseId} @RequestMapping(value ="/view2/{param}",method =RequestMethod.GET) publicvoidviewTest1(PrintWriter out,HttpServletResponse response,@PathVariable("param")String param){ response.setContentType("application/json;charset=UTF-8"); Gson gson =newGsonBuilder().create(); Map<String, Object>map =newHashMap<String, Object>(); map.put("param",param); out.print(gson.toJson(map)); } // /test/view3 @RequestMapping(value ="/view3",method =RequestMethod.POST) publicvoidviewTest2(PrintWriter out,HttpServletResponse response){ response.setContentType("application/json;charset=UTF-8"); Gson gson =newGsonBuilder().create(); Map<String, Object>map =newHashMap<String, Object>(); map.put("status","success"); out.print(gson.toJson(map)); }}
测试代码
publicclassHttpClientTest{ @Test publicvoidtestGet(){ //百度天气的api //String url1 = "http://api.map.baidu.com/telematics/v3/weather?location=%E5%8C%97%E4%BA%AC&output=json&ak=W69oaDTCfuGwzNwmtVvgWfGH"; String url1 ="http://localhost:8080/wechat/test/view2/你好世界"; String result1 =HttpUtil.sendGet(url1); System.out.println(result1); //输出{"param":"你好世界"} } @Test publicvoidtestPost()throwsUnsupportedEncodingException{ String url ="http://localhost:8080/wechat/test/view"; Map<String,String>map =newHashMap<String,String>(); map.put("param1","你好世界"); map.put("param2","哈哈"); String result =HttpUtil.sendPost(url,map); System.out.println(result); //输出结果{"param1":"你好世界","param2":"哈哈"} } @Test publicvoidtestPost1()throwsUnsupportedEncodingException{ String url ="http://localhost:8080/wechat/test/view3"; String result =HttpUtil.sendPost(url); System.out.println(result); //输出结果{"status":"success"} }}
建议通过HttpGet获取信息,HttpPost提交信息,而HttpGet获取信息时需要提交的参数一般会在url中体现,或者以?传参,或者在url中传参,所以就没写HttpGet带参数的。也希望大家能遵循Http的设计原则,通过HttpGet, HttpPost, HttpPut, HttpDelete,来实现获取数据,提交数据,修改数据,和删除数据的方法。
2018年10月25修改
依赖
<!--apache工具类--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.1</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.2</version> <scope>provided</scope> </dependency> <!--httpclient--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.6</version> </dependency> <!--log--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.10</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.2</version> </dependency> <!--MultipartFile--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.6.RELEASE</version> </dependency>
最近优化了一下这个方法,具体程序如下
packagecom.cgw.util;importcom.alibaba.fastjson.JSONObject;importlombok.extern.slf4j.Slf4j;importorg.apache.commons.collections4.CollectionUtils;importorg.apache.commons.collections4.MapUtils;importorg.apache.commons.lang3.StringUtils;importorg.apache.http.Consts;importorg.apache.http.Header;importorg.apache.http.HttpEntity;importorg.apache.http.client.config.RequestConfig;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpGet;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.config.ConnectionConfig;importorg.apache.http.entity.ContentType;importorg.apache.http.entity.StringEntity;importorg.apache.http.entity.mime.HttpMultipartMode;importorg.apache.http.entity.mime.MultipartEntityBuilder;importorg.apache.http.entity.mime.content.StringBody;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClientBuilder;importorg.apache.http.impl.client.HttpClients;importorg.apache.http.message.BasicHeader;importorg.apache.http.util.EntityUtils;importorg.springframework.mock.web.MockMultipartFile;importorg.springframework.web.multipart.MultipartFile;importjava.io.File;importjava.io.FileInputStream;importjava.io.IOException;importjava.nio.charset.Charset;importjava.nio.charset.CodingErrorAction;importjava.nio.file.Files;importjava.nio.file.Path;importjava.nio.file.Paths;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Map;/** * Http工具类 * * @author 程高伟 */@Slf4jpublicclassHttpUtil{ privatestaticfinalString USER_AGENT ="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"; // 超时设置 privatestaticfinalRequestConfig requestConfig =RequestConfig.custom() .setConnectTimeout(5000) .setConnectionRequestTimeout(5000) .setSocketTimeout(10000) .build(); // 编码设置 privatestaticfinalConnectionConfig connectionConfig =ConnectionConfig.custom() .setMalformedInputAction(CodingErrorAction.IGNORE) .setUnmappableInputAction(CodingErrorAction.IGNORE) .setCharset(Consts.UTF_8) .build(); privatestaticHttpClientBuilder getBuilder(){ List<Header>headers =newArrayList<>(); Header header =newBasicHeader("User-Agent",USER_AGENT); headers.add(header); returnHttpClients.custom().setDefaultConnectionConfig(connectionConfig).setDefaultHeaders(headers).setDefaultRequestConfig(requestConfig); } /** * 发送HttpGet请求 * * @param url 请求地址 * @return */ publicstaticString sendGet(String url)throwsIOException { String result; HttpGet httpGet =newHttpGet(url); try(CloseableHttpClient httpclient =getBuilder().build(); CloseableHttpResponse response =httpclient.execute(httpGet)){ HttpEntity httpEntity =response.getEntity(); result =EntityUtils.toString(httpEntity); } returnresult; } /** * 发送HttpPost请求,参数为json字符串 * * @param url 请求地址 * @param jsonStr json字符串 * @return */ publicstaticString sendPost(String url,String jsonStr)throwsIOException { String result; // 设置entity StringEntity stringEntity =newStringEntity(jsonStr,Consts.UTF_8); stringEntity.setContentType("application/json"); HttpPost httpPost =newHttpPost(url); httpPost.setEntity(stringEntity); try(CloseableHttpClient httpclient =getBuilder().build();CloseableHttpResponse httpResponse =httpclient.execute(httpPost);){ HttpEntity httpEntity =httpResponse.getEntity(); result =EntityUtils.toString(httpEntity); } returnresult; } /** * 发送HttpPost请求,提交表单,支持文件上传 * * @param url 请求地址 * @param params 表单参数 * @param files 上传文件 * @return */ publicstaticString sendPost(String url,Map<String, Object>params,List<MultipartFile>files)throwsIOException { String result; // 设置entity MultipartEntityBuilder builder =MultipartEntityBuilder.create(); builder.setCharset(Charset.forName("UTF-8")); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); if(CollectionUtils.isNotEmpty(files)){// 文件表单参数 for(MultipartFile file :files){ Path path =Paths.get(file.getOriginalFilename()); String contentType =Files.probeContentType(path); if(StringUtils.isEmpty(contentType)){ contentType ="application/octet-stream"; } builder.addBinaryBody(file.getName(),file.getInputStream(),ContentType.create(contentType),file.getOriginalFilename()); } } if(MapUtils.isNotEmpty(params)){// 普通表单参数 params.forEach((k,v)->{ StringBody stringBody =newStringBody(v.toString(),ContentType.create("text/plain","UTF-8")); builder.addPart(k,stringBody); }); } HttpPost httpPost =newHttpPost(url); httpPost.setEntity(builder.build());