Java 实现Http请求的概述
前言
最近,项目上要对接几个不同商家提供的第三方接口,这些商家给出的Demo各不相同,一些人对此感到迷惑,在此简单总结一下,以澄清思路。
HTTP协议简述
Http协议是B/S结构程序的理论基础,非常重要,这里简单回顾。
这篇文章介绍比较清楚,需要详细了解,请参考:
https://www.cnblogs.com/coderwhytop/p/14769174.html
本节内容部分参考该文。
概念:
HTTP:HyperText Transfer Protocol(超文本传输协议),用于实现传统的web服务端和客户端之间的通信,是一种无状态协议,短连接协议;是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等),是基于TCP/IP的应用层协议。
Http协议有两个核心内容:
http请求头和http响应头。
1、http请求格式
请求行:
Method:请求方法(GET,POST,PUT,DELETE,OPTION,TRACE…)
URL:请求的资源地址(相对路径)
Version: http协议的版本(默认HTTP1.1)
请求头:
请求头中包含一系列请求参数,这些参数均已键值对结构形式表示,代表请求的配置信息,例如:content-Type:text/html,text/json,/,Cookie: scroll-cookie=0等
空白行:
在发送请求正文时必须保留空白行
请求体:
请求体即需要发送的数据内容:例如: username=admin&password=123456
我们在应用时,需要注意请求方法(GET,POST),Header设定,业务参数设置。
2、HTTP响应格式
根据上图,我可以根据需求解析自己对应的内容,比如,header里的内容,响应正文的内容。
java 调用Http请求的几种方式
1、通过JDK网络类Java.net.HttpURLConnection;
2、通过common封装好的HttpClient;
3、通过Apache封装好的CloseableHttpClient;
4、通过OKhttp3;
以上方式,除了JDK原生包HttpURLConnection外,大体结构相差不大,都主要涉及到几个对象:
1、一个Http请求的客户端对象,一般HttpClient,负责发起请求和接受响应;
2、一个URL,需要请求的URL地址;
3、一个代表本次Http请求的对象,Request;
4、一个代表本次Http响应的对象,Response;
结合具体业务,设置不同请求方法,参数等,即可完成对应请求。
通过JDK网络类Java.net.HttpURLConnection
1、包的引用
通过标题,就可以看到这个是JDK原生包,不用多说,直接上代码
2、代码结构
代码结构:
1)、创建一个URL对象URLObj;
2)、用URLObj创建HttpURLConnection实例httpConn;
3)、设置httpConn的参数;
4)、创建基于httpConn的输出流,用于输出到服务器outputStream;
5)、设置输出流的参数;
6)、把流输出到服务器;outputStream.write()
7)、获取httConn的反馈,得到输入流inputStream
8)、把inputStream转化成BufferReader
9)、通过bufferReader的read()方法,获取结果
3、代码实现
package com.wcd.console.http;
import com.alibaba.fastjson.JSONObject;
import com.mysql.cj.x.protobuf.MysqlxDatatypes;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* HttpURLConnection ,引用 JDK 原生提供的 net
*
*
* @Auther: BeinLai
* @Date: 2023/04/20/10:08
* @Description:
*/
public class HttpURLConnUtils {
public void doPost(String strUrl){
HttpURLConnection conn=null;
BufferedReader reader=null;
StringBuffer resultBuffer=null;
try{
// 创建目标地址
URL url=new URL(strUrl);
//获取连接
conn=(HttpURLConnection)url.openConnection();
//设置请求方法
conn.setRequestMethod("POST");
// 设置请求内容类型,常见的有"application/json" 数据是个json,
// "application/x-www-form-urlencoded" 数据是个普通表单
// multipart/form-data 数据里有文件
conn.setRequestProperty("Content-Type","application/json");
//
conn.setRequestProperty("Authorization","58b24aaa5973564b9edf5e98743fcb2f");
// 允许输入
conn.setDoInput(true);
// 允许输出,POST请求必须设置该属性
conn.setDoOutput(true);
// 不需要缓存
conn.setUseCaches(false);
// 链接服务器
conn.connect();
// 创建一个输出流
OutputStream os=conn.getOutputStream();
// 设置参数
Map<String,String> paraMap=new HashMap<>();
paraMap.put("userName","杨XX");
paraMap.put("jobStatus","1");
// 组装入参
os.write((JSONObject.toJSONString(paraMap)).getBytes());
os.flush();
os.close();
// 获取返回码
int responseCode=conn.getResponseCode();
if(responseCode==HttpURLConnection.HTTP_OK){
// 获取返回输入流
InputStream is=conn.getInputStream();
// 把返回输入流转化成字符串
resultBuffer=new StringBuffer();
String line;
// 创建一个ReadBuffer
reader=new BufferedReader(new InputStreamReader(is,"utf-8"));
while((line=reader.readLine())!=null){
resultBuffer.append(line);
}
reader.close();
System.out.println("result:"+resultBuffer.toString());
}
}catch (Exception e){
e.printStackTrace();
}
}
public void doGet(String strUrl,String params){
HttpURLConnection conn=null;
BufferedReader reader=null;
StringBuffer resultBuffer=null;
try{
// 创建目标地址
URL url=new URL(strUrl.replace("${param}",params));
//获取连接
conn=(HttpURLConnection)url.openConnection();
//设置请求方法
conn.setRequestMethod("GET");
// 设置请求Header内容
conn.setRequestProperty("Content-Type","application/json");
conn.setRequestProperty("Authorization","58b24aaa5973564b9edf5e98743fcb2f");
// 不需要缓存
conn.setUseCaches(false);
// 链接服务器
conn.connect();
// 获取返回码
int responseCode=conn.getResponseCode();
if(responseCode==HttpURLConnection.HTTP_OK){
// 获取返回输入流
InputStream is=conn.getInputStream();
// 把返回输入流转化成字符串
resultBuffer=new StringBuffer();
String line;
// 创建一个ReadBuffer
reader=new BufferedReader(new InputStreamReader(is,"utf-8"));
while((line=reader.readLine())!=null){
resultBuffer.append(line);
}
reader.close();
System.out.println("result:"+resultBuffer.toString());
}
}catch (Exception e){
e.printStackTrace();
}
}
}
通过common封装好的HttpClient
1、Jar包引用
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
2、代码结构:
1)、指定URL;
2)、创建一个HttpClient对象,用于执行httpMethod,比如示例中的PostMethod;
3)、创建PostMethod,参数是url,即针对目标URL创建Method对象;
4)、设置header,设置参数;
5)、使用httpClient对象执行PostMethod,httpClient.executeMethod(postMethod);
6)、处理返回结果,比如code,header,body等;
3、代码实现:
package com.wcd.console.http;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import java.util.HashMap;
import java.util.Map;
/**
* HttpClient,需要用到commons-httpclient-3.1.jar
*
* @Auther: BeinLai
* @Date: 2023/04/20/11:18
* @Description:
*/
public class WcdHttpClientUtils {
public void doPost(){
String strUrl="http://api.f6car.cn/maintain/bill/list";
HttpClient httpClient=new HttpClient();
PostMethod postMethod=new PostMethod(strUrl);
// 设置
postMethod.addRequestHeader("accept","*/*");
//设置Content-Type,此处根据实际情况确定
postMethod.addRequestHeader("Content-Type", "application/json");
String APP_KEY="204169183";
String APP_SECURITY="IdCgwcV3QlnhS68uQeNylYvJakY7Nk60";
//postMethod.setParameter("X-Ca-Key",APP_KEY);
//postMethod.addRequestHeader("X-Ca-Nonce",APP_SECURITY);
Map<String,Object> paraMap=new HashMap<>();
paraMap.put("currentPage",1);
paraMap.put("pageSize",100);
paraMap.put("beginModifiedTime","2023-04-10 14:10:00");
paraMap.put("endModifiedTime","2023-04-10 14:40:00");
postMethod.setParameter("appKey",APP_KEY);
postMethod.setParameter("appSecurity",APP_SECURITY);
postMethod.setParameter("paramValues", JSONObject.toJSONString(paraMap));
String result="1";
try{
int code=httpClient.executeMethod(postMethod);
//Header header= postMethod.getResponseHeader("X-Ca-Error-Code");
Header[] headers=postMethod.getResponseHeaders();
for(Header item:headers){
System.out.println(item.getName()+"="+item.getValue());
}
if(code==200){
result=postMethod.getResponseBodyAsString();
System.out.println(result);
}
} catch(Exception e){
e.printStackTrace();
}
}
}
通过Apache封装好的CloseableHttpClient;
1、添加引用
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
2、代码结构
1)、创建CloseableHttpClient对象;
2)、创建请求配置 RequestConfig;
3)、创建请求方法,Httppost;
4) 、设置参数,List ;
5)、定义响应对象,通过closeablehttpClient的execute方法,获取响应;
6)、根据需要解析响应对象;
3、代码实现
package com.wcd.console.http;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* CloseableHttpClient 需要用到httpclient-4.5.6.jar
*
* @Auther: BeinLai
* @Date: 2023/04/20/11:45
* @Description:
*/
public class CloseableHttpClientUtils {
public void doPost(String url) {
int timeout = 1000 * 10;
// 1、创建CloseableHttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 2、创建请求配置 RequestConfig
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout)
.setSocketTimeout(timeout)
.build();
// 3、创建请求方法
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(requestConfig);
// 4、设置参数
List<NameValuePair> nvps = new ArrayList<>();
Map<String, String> paraMap = new HashMap<>();
paraMap.put("username", "lai");
paraMap.put("password", "wwww");
nvps.add(new BasicNameValuePair("appId", "appKeyVal"));
nvps.add(new BasicNameValuePair("appSecurity", "appSecurityVal"));
nvps.add(new BasicNameValuePair("params", JSONObject.toJSONString(paraMap)));
HttpEntity httpEntity = new UrlEncodedFormEntity(nvps, Consts.UTF_8);
httpPost.setEntity(httpEntity);
CloseableHttpResponse closeableHttpResponse = null;
try {
// 5、定义响应对象,通过closeablehttpClient的execute方法,获取响应
closeableHttpResponse = httpClient.execute(httpPost);
//6、 解析响应对象
HttpEntity respEntity = closeableHttpResponse.getEntity();
String result = EntityUtils.toString(respEntity, Consts.UTF_8);
EntityUtils.consume(respEntity);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
closeableHttpResponse.close();
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
通过OKhttp3;
1、jar包引用
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
2、代码结构
1)、定义OkHttpClient对象httpClient,Http请求的第一步,定义一个请求客户端;
2)、定义Request;
3)、如果是post请求,需要定义RequestBody,来封装请求参数;如果是Get请求,不需要定义,因为Get请求的参数是在URL中;
4)、获取响应对象;httpClient.newCall(request).execute(),或者通过回调处理httpClient.newCall(request).enqueue()定义回调
5)、处理响应
3、代码实现
package com.wcd.console.http;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* OkHttp,需要用到okhttp-3.10.0.jar
*
*
* @Auther: BeinLai
* @Date: 2023/04/20/15:57
* @Description:
*/
public class WcdOkHttpUtils {
private static final OkHttpClient httpClient=new OkHttpClient();
/**
* get
*/
public void doGet1(String strUrl){
Request request=new Request.Builder().url(strUrl).build();
try {
Response response = httpClient.newCall(request).execute();
if (response.isSuccessful()) {
String body = response.body().toString();
System.out.println(body);
} else {
int code = response.code();
System.out.println("请求失败,错误代码:" + code);
}
}catch (IOException ioe){
ioe.printStackTrace();
}
}
/**
* doPost1 :
* // RequestBody 有三种构建方式: FormBodyhe MultiparBody 继承RequestBody
* // 1. FormBody.Builder,构建application/x-www-form-urlencoded类型的post表单
* // 2. MultipartBody.Builder,构建multipart类型的body,多个内容合成到一个body里
* // 3. RequestBody.create方法构建body体,传入两个参数:类型和内容
* RequestBody.create(),RequestBody.create方法构建body体,传入两个参数:类型和内容
*/
public void doPost1(String strUrl,String auth,Map<String,Object> paraMap){
MediaType mediaType=MediaType.parse("application/json;charset=utf-8");
RequestBody requestBody=RequestBody.create(mediaType,JSONObject.toJSONString(paraMap));
Request request=new Request.Builder()
.url(strUrl)
.addHeader("Authorization",auth)
.post(requestBody)
.build();
try {
Response response= httpClient.newCall(request).execute();
Headers headers= response.headers();
Set<String> names=headers.names();
for(String item:names){
System.out.println(item+":"+headers.get(item));
}
int code=response.code();
System.out.println("code="+code);
System.out.println(response.body().string());
}catch (IOException ioe){
ioe.printStackTrace();
}
}
/**
* doPost2
* MultipartBody.Builder,构建multipart类型的body,多个内容合成到一个body里
*/
public void doPost2(String strUrl){
//1、实例化
String authorization="58b24aaa5973564b9edf5e98743fcb2f";
Map<String,Object> paraMap=new HashMap();
paraMap.put("userName","杨飞");
paraMap.put("jobStatus","1");
MultipartBody requestBody=new MultipartBody.Builder()
.addFormDataPart("Authorization",authorization)
.addFormDataPart("userName","杨飞")
.addFormDataPart("paramValues", JSONObject.toJSONString(paraMap))
.build();
// 2、调用之前先实例化一个request
Request request=new Request.Builder()
.url(strUrl)
.post(requestBody)
.addHeader("Content_Type","application/json")
.addHeader("aa","bb")
.addHeader("referer","https://b.fbpic.com/")
.build();
try {
// 3、 构建调用对象并调用
// Call call=httpClient.newCall(request);
// Response rsp = call.execute();
Response rsp = httpClient.newCall(request).execute();
System.out.println("isSuccessFull="+rsp.isSuccessful());
// 返回响应状态码
int code=rsp.code();
// 返回响应内容
ResponseBody responseBody= rsp.body();
System.out.print(responseBody.toString());
}catch (IOException ioe){
ioe.printStackTrace();
}
}
/**
* formBody
* FormBody.Builder,构建application/x-www-form-urlencoded类型的post表单
*/
public void doPost3(String strUrl,String auth,Map<String,Object> params){
for(String keyName:params.keySet()){
String val=params.get(keyName).toString();
}
FormBody formBody=new FormBody.Builder()
.add("key1","val1")
.add("key2","val2")
.addEncoded("key","val3")
.build();
Request request=new Request.Builder()
.url(strUrl)
.post(formBody)
.addHeader("",auth)
.build();
Call call=httpClient.newCall(request);
try {
Response rsp = call.execute();
}catch(IOException ioe){
}
//call.enqueue( );
}
}
综上,简单记录。