前言
对于url的请求两种需求,一种是程序调用接口后返回数据; 二是调用第三方openApi接口。
基于URLConnection的返回值获取
使用java.net包下面原生的URLConnection对象,使用IO流进行数据提交和请求获取,比如说:获取返回结果。
若只是向服务器请求数据,则为HTTP请求方法为GET。
若需要向服务器提交数据,必须在先调用setDoOutput(true)。当doOutput属性为true时,请求方法将由GET变为POST。
使用getInputStream()方法输出的内容只有响应体,不包含响应的首部。
public class WeblistenerTask {
static String flinkURL = "https://api.apiopen.top/getJoke?page=1&count=2&type=video";
//@Scheduled(cron = "00 00 00 * * ?")
public static void weblistener() throws IOException {
StringBuffer result = new StringBuffer();
result.append("niko");
URL url = new URL("https://api.apiopen.top/getJoke?page=1&count=2&type=video");
URLConnection connection = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine())!= null)
{
result.append(line);
}
in.close();
System.err.println(result.toString());
System.err.println( result.toString().contains("running") );
}
public static void main(String[] args) throws IOException {
weblistener();
}
}
使用java.net.URLConnection的子类HttpURLConnection,可以更好的遍历操作http请求,比如说
void setRequestMethod(String method)
基于HttpClient的api请求
依赖引入
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<!-- 三方接口解析-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
消息体的类型
涉及后端的参数注解和请求的Content-Type。
服务端通常是根据请求头
(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码。所以post提交数据应该包括消息头的Content-Type + entity-body(消息主题)。
而对于消息主题常见有四种,不同的Content-Type在后端需要进行不同的入参处理
:
- application/x-www-form-urlencoded:HTTP中默认的提交数据的方式。http://127.0.0.1:9010/test/test2?name=cbry&age=26,对于spring中设置@RequestParam
- multipart/form-data:@RequestPart(“file”) MultipartFile file;
- application/json:
@RequestBody
,@RequestBody 也可以处理 application/xml; - text/xml:类似的有text/html( HTML格式)、text/plain (纯文本格式)等。
PS
:对应的我们想到@RequestMapping(post\get均接受),以及@ResponseBody返回json数据,如上面截图的响应标头。注意restcontroller是集合responsebody。
举个栗子:当后端用的@GetMapping的时候进行post请求就会:
当使用表单:strEntity.setContentType("application/x-www-form-urlencoded");
,提交JSON数据:
这里主要原因还是因为用的StringEntity,这里后面会提及:
HttpPost对象中才有Entity,如果修改成下面代码,则可以进行类似于:http://127.0.0.1:9010/test/test2?name=cbry&age=26的请求:
//发送json数据需要设置contentType
strEntity.setContentType("application/x-www-form-urlencoded");
List nvps = new ArrayList();
nvps.add(new BasicNameValuePair("name", "cbry"));
nvps.add(new BasicNameValuePair("age", "26"));
post.setEntity(new UrlEncodedFormEntity(nvps));
不同的HttpEntity
具体看接口实现类,列举常用的三个
//StringEntity
StringEntity stringEntity = new StringEntity(param);
stringEntity.setContentType("application/x-www-form-urlencoded");
//UrlEncodedFormEntity
List nvps = new ArrayList();
nvps.add(new BasicNameValuePair("name", "cbry"));
nvps.add(new BasicNameValuePair("age", "26"));
httpPost.setEntity(new UrlEncodedFormEntity(nvps)); //param参数,可以为"name=cbry&age=26"的格式参数请求
//MultipartEntity
MultipartEntity entity = new MultipartEntity();
entity.addPart(“param1″, new StringBody(“李四”, Charset.forName(“UTF-8″)));
entity.addPart(“param2″, new StringBody(“男”, Charset.forName(“UTF-8″)));
entity.addPart(“param3″, new FileBody(new File(“C:\\test.txt”)));
HttpClient client = new DefaultHttpClient();
HttpPost postrequest = new HttpPost(url);
HttpClient工具类
分别是带参数的POST/GET请求类方法jsonPostReq,和带JSON的POST请求paramsReq。
package com.cbry.bds.utils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.tomcat.util.buf.StringUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author cbry
* @version 1.0.0
* @ClassName HttpClientUtil
* @createTime 2022年05月17日 14:58:00
*/
@Slf4j
public class HttpClientUtil {
private static RequestConfig requestConfig = null;
static {
//设置http的状态参数 , old: 5000
requestConfig = RequestConfig.custom()
.setSocketTimeout(60000)
.setConnectTimeout(60000)
.setConnectionRequestTimeout(60000)
.build();
}
public static String jsonPostReq(String url , String token, JSONObject jsonObject){
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String result = null;
try {
//请求发起客户端
httpclient = HttpClients.createDefault();
//参数集合
String paramsStr = jsonObject.toString();
//通过post方式访问
HttpPost post = new HttpPost(url);
post.addHeader("token", token);
post.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");
//设置请求参数
//HttpEntity paramEntity = new UrlEncodedFormEntity(paramsStr,"UTF-8");
StringEntity strEntity = new StringEntity(paramsStr);
strEntity.setContentEncoding("UTF-8");
//发送json数据需要设置contentType
strEntity.setContentType("application/json");
post.setEntity(strEntity);
log.info("请求地址:" + post.getURI().toString());
log.info("请求参数:" + EntityUtils.toString(post.getEntity()));
//执行请求
response = httpclient.execute(post);
//返回结果
HttpEntity valueEntity = response.getEntity();
result = EntityUtils.toString(valueEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(httpclient != null){
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(response != null){
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
public static String paramsReq(String url,Map<String, String> paramsMap,String reqMethod) throws IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse response = null;
HttpUriRequest req = null;
//设置参数解析
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (String key : paramsMap.keySet()) {
String value = paramsMap.get(key);
NameValuePair pair = new BasicNameValuePair(key, value);
params.add(pair);
}
//设置请求类型
if (reqMethod.toLowerCase().equals("post")){
req = RequestBuilder.post().setUri(url)
.addParameters(params.toArray(new BasicNameValuePair[params.size()]))
.setConfig(requestConfig).build();
}else{
req = RequestBuilder.get().setUri(url)
.addParameters(params.toArray(new BasicNameValuePair[params.size()]))
.setConfig(requestConfig).build();
}
//设置头
req.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");
response = httpclient.execute(req);
String result = null;
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(httpclient != null){
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(response != null){
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
public static void main(String[] args) throws IOException {
Map<String,String> params = new HashMap<>();
params.put("name","cnry");
params.put("age","26");
System.err.println(paramsReq("http://127.0.0.1:9010/test/test2" ,params , "GET"));
}
// public static void main(String[] args) {
// JSONObject jo= new JSONObject();
// //page=1&count=2&type=video
// jo.put("name",1);
// jo.put("age",2);
// //https://api.apiopen.top/api/getHaoKanVideo
// JSONObject jsonObject = JSONObject.parseObject(jsonPostReq("http://127.0.0.1:9010/test/test" , "" , jo));
// System.out.println( jsonObject );
// }
}
测试的controller方法:
request用来debug中查看paramsMap中的传参。
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@RequestMapping("/test")
public User test(HttpServletRequest request,@RequestBody User user){
return user;
}
@RequestMapping("/test2")
public User test2(HttpServletRequest request, User user){
return user;
}
}
补充
使用hutool工具包,可快捷实现,无须重复轮子:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
比如说:
HttpRequest.post("http://127.0.0.1:8088/bonc/api/taskspec")
.body(params.toString())
.execute().body();
base模板的baseService中有个dao返回值的缘故是:dao继承的类的方法可以不用重复写service方法,减少冗余。
鸣谢
peakchao免费开放接口API
application/json 四种常见的 POST 提交数据方式