本章介绍Java开发中,常见的Http请求方式:
- JAVA的标准类Java.net.
HttpURLConnection
- org.apache.commons.httpclient 封装好的
HttpClient
- Springboot 中
RestTemplate
1. HttpURLConnection
JDK提供的包java.net.HttpURLConnection,HttpURLConnection是JAVA的标准类,是JAVA比较原生的一种实现方式。
POST请求:
public class HttpURLConnectionDemo {
/**
* Http post请求
*/
public static String doPost(String httpUrl, String param) {
HttpURLConnection connection = null;
OutputStream os = null;
InputStream is = null;
BufferedReader br = null;
StringBuffer result = new StringBuffer();
try {
//1.1、创建连接对象
URL url = new URL(httpUrl);
//1.2、创建连接
connection = (HttpURLConnection) url.openConnection();
//2.1、设置请求方法
connection.setRequestMethod("POST");
//2.2、设置连接超时时间 单位:毫秒
connection.setConnectTimeout(15000);
//2.3、设置读取超时时间 单位:毫秒
connection.setReadTimeout(60000);
//2.4、默认值为:false,当向远程服务器传送数据/写数据时,需要设置为true
connection.setDoOutput(true);
// 默认值为:true,当前向远程服务读取数据时,设置为true,该参数可有可无
connection.setDoInput(true);
//2.5、设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
//3、写需要发送的请求
if (null != param && !param.equals("")) {
//设置参数
os = connection.getOutputStream();
//拼装参数
os.write(param.getBytes("UTF-8"));
}
//4、读取响应
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
is = connection.getInputStream();
if (null != is) {
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String temp = null;
while (null != (temp = br.readLine())) {
result.append(temp);
result.append("\r\n");
}
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭连接
connection.disconnect();
}
return result.toString();
}
public static void main(String[] args) throws IOException {
String post = doPost("http://127.0.0.1:8080/postHttp", "{\"id\":\"1001\",\"name\":\"丽丽\"}");
System.out.println(post);
}
}
get请求:
public class HttpURLConnectionDemo {
/**
* Http get请求
*/
public static String doGet(String httpUrl){
HttpURLConnection connection = null;
InputStream is = null;
BufferedReader br = null;
StringBuffer result = new StringBuffer();
try {
//1、创建连接对象
URL url = new URL(httpUrl);
connection = (HttpURLConnection) url.openConnection();
//2.1、设置请求方法
connection.setRequestMethod("GET");
//2.2、设置连接超时时间 单位:毫秒
connection.setReadTimeout(15000);
//3、开始连接
connection.connect();
//4、获取响应数据
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
//获取返回的数据
is = connection.getInputStream();
if (null != is) {
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String temp = null;
while (null != (temp = br.readLine())) {
result.append(temp);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭远程连接
connection.disconnect();
}
return result.toString();
}
public static void main(String[] args) throws IOException {
String get = doGet("http://127.0.0.1:8080/getHttp?id=1001");
System.out.println(get);
}
}
get请求下载图片:
和上面的get请求一样,只是响应数据用字节流接收,保存到指定目录。
public class HttpURLConnectionDemo {
/**
* Http get请求下载图片
*/
public static void downLoad(String httpUrl){
HttpURLConnection connection = null;
InputStream is = null;
BufferedInputStream fis = null;
BufferedOutputStream fio = null;
try {
//1、创建连接对象
URL url = new URL(httpUrl);
connection = (HttpURLConnection) url.openConnection();
//2.1、设置请求方法
connection.setRequestMethod("GET");
//2.2、设置连接超时时间 单位:毫秒
connection.setReadTimeout(15000);
//3、开始连接
connection.connect();
//4、获取响应数据
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
//获取返回的数据
is = connection.getInputStream();
if (null != is) {
fis = new BufferedInputStream(is);
fio = new BufferedOutputStream(new FileOutputStream("e:\\demo\\test.jpg"));
// 一次读取一个字节数组
int len = 0;
byte[] bys = new byte[1024];
while ( (len = fis.read(bys)) != -1 ){
System.out.print(len);
fio.write(bys, 0, len);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != fis) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != fio) {
try {
fio.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭远程连接
connection.disconnect();
}
}
public static void main(String[] args) throws IOException {
downLoad("https://img-s-msn-com.akamaized.net/tenant/amp/entityid/AA1lY20g.img?w=534&h=413&m=6&x=619&y=126&s=168&d=168");
}
}
服务端使用springboot项目:
@RestController
public class HelloController {
@RequestMapping("/postHttp")
public String testHttp(@RequestBody Map<String, Object> map){
System.out.println(map);
return "post http" ;
}
@RequestMapping("/getHttp")
public String testHttp(@RequestParam String id){
System.out.println(id);
return "get http" ;
}
}
2. HttpClient
HTTPClient 对 HTTP 的封装性比较不错,通过它基本上能够满足我们大部分的需求,HttpClient3.1 是 org.apache.commons.httpclient 下操作远程 url 的工具包,虽然已不再更新,但实现工作中使用 httpClient3.1 的代码还是很多。HttpClient4.5 是org.apache.http.client下操作远程 url 最新的工具包。
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
POST请求:
public class HttpClientDemo {
/**
* httpClient 的 post 请求方式
* 使用 PostMethod 来访问一个 URL 对应的网页实现步骤:
* 1.生成一个 HttpClient 对象并设置相应的参数;
* 2.生成一个 PostMethod 对象并设置响应的参数;
* 3.用 HttpClient 生成的对象来执行 PostMethod 生成的 POST 方法;
* 4.处理 HTTP 响应内容
* 5.释放连接。
*/
public static String doPost(String url, String jsonString, String charset) {
HttpClient httpClient = null;
PostMethod postMethod = null;
String response = "";
InputStream is = null;
BufferedReader br = null;
//1.1、生成HttpClient对象并设置参数
httpClient = new HttpClient();
//1.2、设置连接超时时间 单位:毫秒
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(15000);
//2.1、生成GetMethod对象并设置参数
postMethod = new PostMethod(url);
//2.2、设置post请求参数
postMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 60000);
postMethod.addRequestHeader("accept", "*/*");
postMethod.addRequestHeader("connection", "Keep-Alive");
postMethod.addRequestHeader("Content-Type", "application/json;charset=utf-8");
postMethod.addRequestHeader("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");
//2.3、添加请求参数
try {
postMethod.setRequestEntity(new StringRequestEntity(jsonString, "application/json", "utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
//3、执行HTTP POST 请求
int statusCode = httpClient.executeMethod(postMethod);
//4.1、判断返回的状态码
if (statusCode == HttpStatus.SC_OK){
//4.2、处理HTTP响应头
Header[] headers = postMethod.getResponseHeaders();
for(Header h : headers) {
System.out.println(h.getName() + "headers:" + h.getValue());
}
//4.3、处理HTTP响应体 方式一:
/*byte[] responseBody = postMethod.getResponseBody();
response = new String(responseBody, charset);
System.out.println("response:" + response);*/
//方式二:
is = postMethod.getResponseBodyAsStream();
br = new BufferedReader(new InputStreamReader(is, charset));
StringBuffer sbf = new StringBuffer();
String temp = null;
while ((temp = br.readLine()) != null) {
sbf.append(temp).append("\r\n");
}
System.out.println("response:" + sbf);
response = sbf.toString();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 5、释放连接
postMethod.releaseConnection();
}
return response;
}
public static void main(String[] args) throws IOException {
String post = doPost("http://127.0.0.1:8080/postHttp", "{\"id\":\"1001\",\"name\":\"丽丽\"}", "UTF-8");
System.out.println("post:" + post);
}
}
get请求:
public class HttpClientDemo {
/**
* httpClient的get请求方式
* 使用GetMethod来访问一个URL对应的网页实现步骤:
* 1.生成一个 HttpClient 对象并设置相应的参数;
* 2.生成一个 GetMethod 对象并设置响应的参数;
* 3.用 HttpClient 生成的对象来执行 GetMethod 生成的 Get 方法;
* 4.处理HTTP响应内容
* 5.释放连接。
*/
public static String doGet(String url, String charset) {
HttpClient httpClient = null;
GetMethod getMethod = null;
String response = "";
InputStream is = null;
BufferedReader br = null;
//1.1、生成HttpClient对象并设置参数
httpClient = new HttpClient();
//1.2、设置连接超时时间 单位:毫秒
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(15000);
//2.1、生成GetMethod对象并设置参数
getMethod = new GetMethod(url);
//2.2、设置get请求超时时间 单位:毫秒
getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 60000);
//2.3、设置请求重试处理,用的是默认的重试处理:请求三次
getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
try {
//3、执行HTTP GET 请求
int statusCode = httpClient.executeMethod(getMethod);
//4.1、判断返回的状态码
if (statusCode != HttpStatus.SC_OK) {
System.err.println("请求出错:" + getMethod.getStatusLine());
}
//4.2、处理HTTP响应头
Header[] headers = getMethod.getResponseHeaders();
for(Header h : headers) {
System.out.println(h.getName() + "headers:" + h.getValue());
}
//4.3、处理HTTP响应体 方式一:
/*byte[] responseBody = getMethod.getResponseBody();
response = new String(responseBody, charset);
System.out.println("response:" + response);*/
//方式二:
//读取为InputStream,在网页内容数据量大时候推荐使用
is = getMethod.getResponseBodyAsStream();
br = new BufferedReader(new InputStreamReader(is, charset));
StringBuffer sbf = new StringBuffer();
String temp = null;
while ((temp = br.readLine()) != null) {
sbf.append(temp).append("\r\n");
}
System.out.println("response:" + sbf);
response = sbf.toString();
} catch (HttpException e) {
System.out.println("请检查输入的URL!");
e.printStackTrace();
} catch (IOException e) {
//发生网络异常
System.out.println("发生网络异常!");
} finally {
// 关闭资源
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 5、释放连接
getMethod.releaseConnection();
}
return response;
}
public static void main(String[] args) throws IOException {
String get = doGet("http://127.0.0.1:8080/getHttp?id=1001", "UTF-8");
System.out.println("get:" + get);
}
}
服务端使用springboot项目:
@RestController
public class HelloController {
@RequestMapping("/postHttp")
public String testHttp(@RequestBody Map<String, Object> map){
System.out.println(map);
return "post http" ;
}
@RequestMapping("/getHttp")
public String testHttp(@RequestParam String id){
System.out.println(id);
return "get http" ;
}
}
📌 访问https网址需要配置ssl证书,可以参考 📖 轻松把玩HttpClient之配置ssl,采用绕过证书验证实现https
📌 Java使用HttpClient以multipart/form-data向接口上传文件
3. RestTemplate
RestTemplate内容过多,放在下章介绍。
引用文章:
📖java实现HTTP请求的三种方式
📖Java中实现http请求的方式
4. 应答信息乱码问题
应答信息乱码问题主要原因分为两种,体现在响应报文头的两个属性:
Content-Type
:text/xml、binary、application/json、text/plain等Content-Encoding
:gzip(最常用)、compress、deflate、identity、br(brotli)
Content-Type
响应的属性是application/json encoding=utf-8
,这种情况需要指定输入流使用utf-8
编码解析,不然会中文乱码。
InputStream is = null;
BufferedReader br = null;
StringBuffer result = new StringBuffer();
is = connection.getInputStream();
// 指定输入流使用 UTF-8
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String temp = null;
while (null != (temp = br.readLine())) {
result.append(temp);
}
Content-Encoding
一般 REST 接口返回明文 JSON 数据,该属性返回null
。对于返回大数据的情况,一般会对返回报文进行压缩,再进行传输,压缩方式放在属性 Content-Encoding
中指定。
常用压缩算法是 gzip
,2015 年 9 月 Google 推出了无损压缩算法 Brotli
。与其他压缩算法相比,它有着更高的压塑压缩效率。启用 Brotli 压缩算法,对比 Gzip 压缩 CDN 流量再减少 20%。
Brotli算法压缩的返回报文头属性 Content-Encoding=br,br 是 Brotli 的简写。
如果用上述的 GET 方法进行接收,因为数据是经过 br 压缩的,所以会输出乱码。
解决方案:对接收数据进行解码。
gzip:
解码工具包含在 java.util.zip.GZIPInputStream
import java.util.zip.GZIPInputStream;
...
//4、获取响应数据
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// 获取返回的数据
is = connection.getInputStream();
// gzip解码
GZIPInputStream gzipInputStream = new GZIPInputStream(is);
if (null != is) {
br = new BufferedReader(new InputStreamReader(gzipInputStream, "UTF-8"));
String temp = null;
while (null != (temp = br.readLine())) {
result.append(temp);
}
System.out.println(connection.getContentEncoding());
}
}
br(brotli):
需要引入依赖:
<dependency>
<groupId>org.brotli</groupId>
<artifactId>dec</artifactId>
<version>0.1.2</version>
</dependency>
import org.brotli.dec.BrotliInputStream;
...
//4、获取响应数据
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// 获取返回的数据
is = connection.getInputStream();
// Brotli解码
BrotliInputStream brotliInputStream = new BrotliInputStream(is);
if (null != is) {
br = new BufferedReader(new InputStreamReader(brotliInputStream, "UTF-8"));
String temp = null;
while (null != (temp = br.readLine())) {
result.append(temp);
}
System.out.println(connection.getContentEncoding());
}
}
📖 HttpURLConnection使用GET请求时应答信息乱码问题
📖 解析接口返回报文,压缩格式为br(brotli)乱码解决
后来发现了 Hutool-http,可以非常方便地上传下载文件,推荐读者们去尝试一下。