55 | JAVA_HTTP编程
2022/9/6 14:34:10
本文主要是介绍55 | JAVA_HTTP编程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
HTTP编程
基础知识
什么是HTTP?HTTP就是目前使用最广泛的Web应用程序使用的基础协议,例如,浏览器访问网站,手机App访问后台服务器,都是通过HTTP协议实现的。
一个完整的HTTP请求-响应如下:
GET / HTTP/1.1 Host: www.sina.com.cn User-Agent: Mozilla/5 MSIE Accept: */* ┌────────┐ ┌─────────┐ Accept-Language: zh-CN,en │░░░░░░░░│ │O ░░░░░░░│───────────────────────────>├────────┤ ├─────────┤<───────────────────────────│░░░░░░░░│ │ │ HTTP/1.1 200 OK ├────────┤ │ │ Content-Type: text/html │░░░░░░░░│ └─────────┘ Content-Length: 133251 └────────┘ Browser <!DOCTYPE html> Server <html><body> <h1>Hello</h1> ...
- 如果是
GET
请求,那么该HTTP请求只有HTTP Header,没有HTTP Body。如果是POST
请求,那么该HTTP请求带有Body,以一个空行分隔。一个典型的带Body的HTTP请求如下:
POST /login HTTP/1.1 Host: www.example.com Content-Type: application/x-www-form-urlencoded Content-Length: 30 username=hello&password=123456
POST
请求通常要设置Content-Type
表示Body的类型,Content-Length
表示Body的长度,这样服务器就可以根据请求的Header和Body做出正确的响应。
GET
请求的参数必须附加在URL上,并以URLEncode方式编码,例如:http://www.example.com/?a=1&b=K%26R
,参数分别是a=1
和b=K&R
。因为URL的长度限制,GET
请求的参数不能太多,而POST
请求的参数就没有长度限制,因为POST
请求的参数必须放到Body中。并且,POST
请求的参数不一定是URL编码,可以按任意格式编码,只需要在Content-Type
中正确设置即可。常见的发送JSON的POST
请求如下:
POST /login HTTP/1.1 Content-Type: application/json Content-Length: 38 {"username":"bob","password":"123456"}
- HTTP/1.0协议
对于最早期的HTTP/1.0协议,每次发送一个HTTP请求,客户端都需要先创建一个新的TCP连接,然后,收到服务器响应后,关闭这个TCP连接。由于建立TCP连接就比较耗时,因此,为了提高效率,HTTP/1.1协议允许在一个TCP连接中反复发送-响应,这样就能大大提高效率:
┌─────────┐ ┌─────────┐ │░░░░░░░░░│ │O ░░░░░░░│ ├─────────┤ ├─────────┤ │░░░░░░░░░│ │ │ ├─────────┤ │ │ │░░░░░░░░░│ └─────────┘ └─────────┘ │ request 1 │ │─────────────────────>│ │ response 1 │ │<─────────────────────│ │ request 2 │ │─────────────────────>│ │ response 2 │ │<─────────────────────│ │ request 3 │ │─────────────────────>│ │ response 3 │ │<─────────────────────│ ▼ ▼
- HTTP/2.0
HTTP/2.0允许客户端在没有收到响应的时候,发送多个HTTP请求,服务器返回响应的时候,不一定按顺序返回,只要双方能识别出哪个响应对应哪个请求,就可以做到并行发送和接收:
┌─────────┐ ┌─────────┐ │░░░░░░░░░│ │O ░░░░░░░│ ├─────────┤ ├─────────┤ │░░░░░░░░░│ │ │ ├─────────┤ │ │ │░░░░░░░░░│ └─────────┘ └─────────┘ │ request 1 │ │─────────────────────>│ │ request 2 │ │─────────────────────>│ │ response 1 │ │<─────────────────────│ │ request 3 │ │─────────────────────>│ │ response 3 │ │<─────────────────────│ │ response 2 │ │<─────────────────────│ ▼ ▼
关于客户端的HTTP编程(和爬虫一个道理)
Java标准库提供了基于HTTP的包,但是要注意,早期的JDK版本是通过HttpURLConnection
访问HTTP,典型代码如下:
URL url = new URL("http://www.example.com/path/to/target?a=1&b=2"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setUseCaches(false); conn.setConnectTimeout(5000); // 请求超时5秒 // 设置HTTP头: conn.setRequestProperty("Accept", "*/*"); conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 11; Windows NT 5.1)"); // 连接并发送HTTP请求: conn.connect(); // 判断HTTP响应是否200: if (conn.getResponseCode() != 200) { throw new RuntimeException("bad response"); } // 获取所有响应Header: Map<String, List<String>> map = conn.getHeaderFields(); for (String key : map.keySet()) { System.out.println(key + ": " + map.get(key)); } // 获取响应内容: InputStream input = conn.getInputStream(); ...
上述代码编写比较繁琐,并且需要手动处理InputStream
,所以用起来很麻烦。
从Java 11开始,引入了新的HttpClient
,它使用链式调用的API,能大大简化HTTP的处理。
我们来看一下如何使用新版的HttpClient
。首先需要创建一个全局HttpClient
实例,因为HttpClient
内部使用线程池优化多个HTTP连接,可以复用:
static HttpClient httpClient = HttpClient.newBuilder().build();
使用GET
请求获取文本内容代码如下:
import java.net.URI; import java.net.http.*; import java.net.http.HttpClient.Version; import java.time.Duration; import java.util.*; public class Main { // 全局HttpClient: static HttpClient httpClient = HttpClient.newBuilder().build(); public static void main(String[] args) throws Exception { String url = "https://www.sina.com.cn/"; HttpRequest request = HttpRequest.newBuilder(new URI(url)) // 设置Header: .header("User-Agent", "Java HttpClient").header("Accept", "*/*") // 设置超时: .timeout(Duration.ofSeconds(5)) // 设置版本: .version(Version.HTTP_2).build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // HTTP允许重复的Header,因此一个Header可对应多个Value: Map<String, List<String>> headers = response.headers().map(); for (String header : headers.keySet()) { System.out.println(header + ": " + headers.get(header).get(0)); } System.out.println(response.body().substring(0, 1024) + "..."); } }
如果我们要获取图片这样的二进制内容,只需要把HttpResponse.BodyHandlers.ofString()
换成HttpResponse.BodyHandlers.ofByteArray()
,就可以获得一个HttpResponse<byte[]>
对象。如果响应的内容很大,不希望一次性全部加载到内存,可以使用HttpResponse.BodyHandlers.ofInputStream()
获取一个InputStream
流。
要使用POST
请求,我们要准备好发送的Body数据并正确设置Content-Type
:
String url = "http://www.example.com/login"; String body = "username=bob&password=123456"; HttpRequest request = HttpRequest.newBuilder(new URI(url)) // 设置Header: .header("Accept", "*/*") .header("Content-Type", "application/x-www-form-urlencoded") // 设置超时: .timeout(Duration.ofSeconds(5)) // 设置版本: .version(Version.HTTP_2) // 使用POST并设置Body: .POST(BodyPublishers.ofString(body, StandardCharsets.UTF_8)).build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); String s = response.body();
可见发送POST
数据也十分简单。
这篇关于55 | JAVA_HTTP编程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-0601-电商商品中心解密:仅凭SKU真的足够吗?
- 2024-05-01为什么公共事业机构会偏爱 TiDB :TiDB 数据库在某省妇幼健康管理系统的应用
- 2024-04-26敏捷开发:想要快速交付就必须舍弃产品质量?
- 2024-04-26静态代码分析的这些好处,我竟然都不知道?
- 2024-04-26你在测试金字塔的哪一层?(下)
- 2024-04-26快刀斩乱麻,DevOps让代码评审也自动起来
- 2024-04-262024年最好用的10款ER图神器!
- 2024-04-2203-为啥大模型LLM还没能完全替代你?
- 2024-04-2101-大语言模型发展
- 2024-04-17基于SpringWeb MultipartFile文件上传、下载功能