一、前言
在Java web系统中经常需要与外部接口进行对接,比较多的方式就是是http的方式。在springboot中,我们可以直接使用封装的feign如:我们去请求微信的接口,定义一个client客户端,使用feign框架去请求就可以。但是也有很多系统没有使用feign的框架,那就需要使用http工具类了。
@FeignClient(name = "weixin", url = "https://api.weixin.qq.com/")
public interface WXCLient {
/**
* 获取微信token
* @param appid
* @param secret
* @return
*/
@GetMapping("cgi-bin/token")
Map<String, Object> gettoken(@RequestParam("appid") String appid,
@RequestParam("secret") String secret, @RequestParam("grant_type") String grant_type);
/**
* 获取微信token
*
* @param appid
* @param secret
* @return
*/
@GetMapping("cgi-bin/token")
Map<String, Object> getQRtoken(@RequestParam("appid") String appid, @RequestParam("secret") String secret, @RequestParam("grant_type") String grant_type);
/**
* 小程序登录
*
* @param appid
* @param secret
* @param grant_type
* @param jsCode
* @return map {"session_key": "", "openid": ""}
*/
@GetMapping("sns/jscode2session")
Map<String, Object> jscode2session(@RequestParam("appid") String appid, @RequestParam("secret") String secret, @RequestParam("grant_type") String grant_type, @RequestParam("js_code") String jsCode);
/**
* 根据access_token和code获取微信登录信息
*
* @param access_token
* @param code
* @return
*/
@GetMapping("cgi-bin/user/getUserInfo")
Map<String, Object> getuserinfo(@RequestParam("access_token") String access_token, @RequestParam("code") String code);
/**
* @param access_token
* @param userId
* @return
*/
@GetMapping("cgi-bin/user/get")
Map<String, Object> get(@RequestParam("access_token") String access_token, @RequestParam("userid") String userId);
/**
* 获取微信用户手机号
*
* @param bodyMap
* @param accessToken
* @return
*/
@PostMapping("wxa/business/getuserphonenumber")
Map<String, Object> getPhone(@RequestParam("access_token") String accessToken, @RequestBody Map<String, Object> bodyMap);
/**
* 创建特定路径的微信小程序二维码
*
* @param bodyMap {"path":"", "with": 430}
* @param accessToken
* @return 返回的图片 Buffer
*/
@PostMapping("cgi-bin/wxaapp/createwxaqrcode")
Response createwxaqrcode(@RequestParam("access_token") String accessToken, @RequestBody Map<String, Object> bodyMap);
/**
* 获取urlscheme
* @param accessToken
* @param bodyMap
* @return
*/
@PostMapping("wxa/generatescheme")
Map<String, Object> generatescheme(@RequestParam("access_token") String accessToken, @RequestBody Map<String, Object> bodyMap);
/**
* 通过短信链接跳转
* 获取generate_urllink
* @param accessToken
* @param bodyMap
* @return
*/
@PostMapping("wxa/generate_urllink")
Map<String, Object> generateUrllink(@RequestParam("access_token") String accessToken, @RequestBody Map<String, Object> bodyMap);
/**
* 二维码
*该接口用于获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。
* @param accessToken
* @param bodyMap
* @return
*/
@PostMapping("wxa/getwxacodeunlimit")
byte[] getwxacodeunlimit(@RequestParam("access_token") String accessToken, @RequestBody Map<String, Object> bodyMap);
/**
* 二维码
*该接口用于获取小程序码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制,详见获取小程序码。
* @param accessToken
* @param bodyMap
* @return
*/
@PostMapping("wxa/getwxacode")
byte[] getwxacode(@RequestParam("access_token") String accessToken, @RequestBody Map<String, Object> bodyMap);
}
二、http工具类
public class HttpUtils {
private static Log logger = LogFactory.getLog(HttpUtils.class);
public static String doGet(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
// 创建http GET请求
HttpGet httpGet = new HttpGet(uri);
// 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doGet(String url) {
return doGet(url, null);
}
public static String doPost(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(3000)
.setSocketTimeout(3000).setConnectTimeout(3000).build();
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setConfig(requestConfig);
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, (String) param.get(key)));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, "utf-8");
httpPost.setEntity(entity);
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url, Map<String, String> param, Map<String, String> headerParam) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(10000)
.setSocketTimeout(10000).setConnectTimeout(10000).build();
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setConfig(requestConfig);
if (headerParam != null) {
for (Map.Entry<String, String> entry : headerParam.entrySet()) {
httpPost.setHeader(entry.getKey(), entry.getValue());
}
}
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, (String) param.get(key)));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, "utf-8");
httpPost.setEntity(entity);
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
logger.error("请求异常", e);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPostJson(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json");
String jsonStr = JSONUtility.objectToJson(param);
logger.info("post json parm:" + jsonStr);
// 创建参数列表
httpPost.setEntity(new StringEntity(jsonStr, "UTF-8"));
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url) {
return doPost(url, null);
}
public static String jsonPostHttps(String url, JSONObject params, int connectTimeout) {
String responseContent = null;
HttpPost httpPost = new HttpPost(url);
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(connectTimeout)
.setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectTimeout).build();
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setEntity(new StringEntity(params.toString(), Consts.UTF_8));
httpPost.setConfig(requestConfig);
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
// 执行POST请求
HttpEntity entity = response.getEntity(); // 获取响应实体
try {
if (null != entity) {
responseContent = EntityUtils.toString(entity, Consts.UTF_8);
}
} finally {
if (entity != null) {
entity.getContent().close();
}
}
} finally {
if (response != null) {
response.close();
}
}
} catch (ClientProtocolException e) {
} catch (IOException e) {
} finally {
httpPost.releaseConnection();
}
return responseContent;
}
public static String doPostJson(String url, String json) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json");
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPostJson(String url, String json, Map<String, String> headerParam) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json");
if (headerParam != null) {
for (Map.Entry<String, String> entry : headerParam.entrySet()) {
httpPost.setHeader(entry.getKey(), entry.getValue());
}
}
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPostStream(String url, Map<String, String> param, Map<String, InputStream> streamMap) {
// MultipartEntityBuilder;
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
MultipartEntityBuilder meBuilder = MultipartEntityBuilder.create();
if (param != null) {
for (String key : param.keySet()) {
meBuilder.addPart(key, new StringBody((String) param.get(key), ContentType.APPLICATION_JSON));
}
}
if (streamMap != null) {
for (String key : streamMap.keySet()) {
InputStreamBody inputStreamBody = new InputStreamBody(streamMap.get(key), key);
meBuilder.addPart(key, inputStreamBody);
}
}
HttpEntity entity = meBuilder.build();
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url, Map<String, String> param, int connectTimeout) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectTimeout)
.setSocketTimeout(connectTimeout).setConnectTimeout(connectTimeout).build();
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setConfig(requestConfig);
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, (String) param.get(key)));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, "utf-8");
httpPost.setEntity(entity);
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url, String param, String contentType, int connectTimeout) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectTimeout)
.setSocketTimeout(connectTimeout).setConnectTimeout(connectTimeout).build();
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", contentType);
httpPost.setConfig(requestConfig);
// 创建参数列表
if (param != null) {
// List<NameValuePair> paramList = new ArrayList<>();
// for (String key : param.keySet()) {
// paramList.add(new BasicNameValuePair("key", (String) param.get(key)));
// }
// // 模拟表单
// UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, "utf-8");
httpPost.setEntity(new StringEntity(param, Consts.UTF_8));
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
三、http请求数据和响应数据详解
HTTP请求数据
HTTP请求通常由四部分组成:请求行、请求头部、空行和请求体(如果有的话)。
-
请求行:
- 请求方法:如GET、POST、PUT、DELETE等。它告诉服务器你想要执行的操作类型。
- URL:请求的资源的路径。
- HTTP协议版本:客户端使用的HTTP协议版本,通常是HTTP/1.1。
-
请求头部:包含一系列键值对,提供了关于请求和客户端的额外信息。例如:
- Host:请求的目标主机。
- User-Agent:发送请求的客户端的类型和版本。
- Accept:客户端可以处理的内容类型。
- Content-Type:请求体的媒体类型(如果有的话)。
- Content-Length:请求体的长度(如果有的话)。
-
空行:请求头部之后是一个空行,用于分隔请求头部和请求体。
-
请求体:包含发送给服务器的数据,通常用于POST和PUT请求。
HTTP响应数据
HTTP响应也由四部分组成:状态行、响应头部、空行和响应体。
-
状态行:
- HTTP协议版本:服务器使用的HTTP协议版本。
- 状态码:一个三位数,表示请求的处理结果,如200表示成功,404表示未找到资源等。
- 状态消息:对状态码的简短描述。
-
响应头部:与请求头部类似,包含一系列键值对,提供了关于响应和服务器的额外信息。例如:
- Content-Type:响应体的媒体类型。
- Content-Length:响应体的长度。
- Date:响应生成的日期和时间。
- Server:服务器软件的名称和版本。
-
空行:响应头部之后是一个空行,用于分隔响应头部和响应体。
-
响应体:包含服务器返回给客户端的数据,通常是HTML、JSON或其他类型的内容。
四、TCP的三次握手
HTTP通常建立在TCP之上,因此,当我们在谈论网络请求时,实际上在底层是通过TCP来建立和维护连接的。
以下是TCP三次握手的简要概述:
- SYN(同步)阶段:
- 客户端向服务器发送一个SYN包,并等待服务器确认。SYN包中包含客户端的初始序列号。
- SYN-ACK(同步-应答)阶段:
- 服务器收到SYN包后,向客户端发送一个SYN-ACK包作为应答。这个包中包含对客户端SYN包的确认信息(ACK)以及服务器自己的初始序列号。
- ACK(应答)阶段:
- 客户端收到SYN-ACK包后,再向服务器发送一个ACK包,此包包含对服务器SYN-ACK包的确认信息。
完成这三次握手后,TCP连接就建立起来了,之后客户端和服务器就可以开始传输数据了。