首先引入依赖
org.springframework.boot
spring-boot-starter-web
编写配置类
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);//单位为ms
factory.setConnectTimeout(5000);//单位为ms
return factory;
}
}
SimpleClientHttpRequestFactory类对应的HTTP库是JDK自带的HttpUrlConnection,也可以修改使用其他的HTTP库,例如HttpComponentsAsyncClientHttpRequestFactory。
这样就可以注入使用了
@Resource
private RestTemplate restTemplate;
String url = "http://127.0.0.1/test";
// 请求参数
Map map = new HashMap<>();
map.put("key", "111");
// 设置请求头属性
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity httpEntity = new HttpEntity(map, httpHeaders);
String results = restTemplate.postForObject(url, httpEntity, String.class);
Spring3.0引入了RestTemplate,WebClient是Spring Framework的一部分,但是在后来的官方源码中介绍,RestTemplate有可能在未来的版本中被弃用,所谓替代RestTemplate,在Spring5中引入了WebClient作为异步的非阻塞、响应式的HTTP客户端。
依赖
org.springframework.boot
spring-boot-starter-webflux
使用
public class TestWebClient {
@Test
public void doGet() {
String userId = "郭郭";
String url = "http://127.0.0.1:8094/masterdata/sysUser/getSysUserById?userId={userId}";
Mono mono = WebClient
//创建WebClient实例
.create()
//方法调用,WebClient中提供了多种方法
.get()
//请求url
.uri(url, userId)
//获取响应结果
.retrieve()
//将结果转换为指定类型
.bodyToMono(String.class);
//返回最终结果:block是阻塞的/subscribe()非阻塞式获取响应结果
System.out.println("响应结果:" + mono.block());
}
@Test
public void doPost() {
Map map = new HashMap<>();
map.put("name", "郭郭");
String requestBody = JSON.toJSONString(map);
String url = "http://127.0.0.1:8094/masterdata/sysUser/saveUser";
Mono mono = WebClient
//创建WebClient实例
.create()
//方法调用,WebClient中提供了多种方法
.post()
//请求url
.uri(url)
//指定请求的Content-Type为JSON
.contentType(MediaType.APPLICATION_JSON)
//使用bodyValue方法传递请求体
.bodyValue(requestBody)
//获取响应结果
.retrieve()
//将结果转换为指定类型
.bodyToMono(String.class);
//返回最终结果:block是阻塞的/subscribe()非阻塞式获取响应结果
System.out.println("响应结果:" + mono.block());
}
}
在上述doPost请求中,我们的请求接口入参是一个Map,但是需要转换为JSON格式传递,这是因为WebClient默认是使用JSON序列化的。
引入依赖
org.apache.httpcomponents.client5
httpclient5
5.1.1
//步骤一:方式1获取默认配置的httpClient实例
CloseableHttpClient httpClient = HttpClients.createDefault();
// 方式2根据系统配置创建 HttpClient
// CloseableHttpClient httpClient = HttpClients.createSystem();
// 在项目启动时可以通过设置如下JVM启动参数:
// http.agent 配置 userAgent
// http.keepAlive 配置 keepAlive 数据
// 方式3自定义创建全局配置
// CloseableHttpClient httpClient = HttpClients.custom()
// .setDefaultHeaders(Collections.emptyList()) // 设置默认请求头
// .setDefaultRequestConfig(RequestConfig.DEFAULT) // 设置默认配置
// .build();
// 设置默认请求头
List headers = new ArrayList<>();
headers.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON));
headers.add(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, x-gzip, deflate"));
headers.add(new BasicHeader(HttpHeaders.CONNECTION, "keep-alive"));
httpClient .setDefaultHeaders(headers)
//步骤二:创建HTTP请求
HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/masterdata/sysUser/getSysUserById?userId=张三");
// 创建请求配置信息
RequestConfig requestConfig = RequestConfig.custom()
// 设置连接超时时间
.setConnectTimeout(Timeout.of(3000, TimeUnit.MILLISECONDS))
// 设置响应超时时间
.setResponseTimeout(3000, TimeUnit.MILLISECONDS)
// 设置从连接池获取链接的超时时间
.setConnectionRequestTimeout(3000, TimeUnit.MILLISECONDS)
.build();
// 设置请求参数
httpGet.setConfig(requestConfig);
// 添加 Content-Type 请求头
httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED);
// 添加 accept 请求头
httpPost.addHeader(new BasicHeader(HttpHeaders.ACCEPT, "*/*"));
//步骤三:发送请求并获取响应数据
CloseableHttpResponse response = httpClient.execute(httpGet);
// 获取请求状态
int code = response.getCode();
//步骤四:处理响应数据
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
//步骤五:关闭httpClient和response
response.close();
httpClient.close();
// 构建请求路径,及参数
URL url = new URL("http://localhost:10010/user/params");
URI uri = new URIBuilder()
.setScheme(url.getProtocol())
.setHost(url.getHost())
.setPort(url.getPort())
.setPath(url.getPath())
// 构建参数
.setParameters(
new BasicNameValuePair("name", "张三"),
new BasicNameValuePair("age", "20")
).build();
// 创建 GET 请求对象
HttpGet httpGet = new HttpGet(uri);
// 调用 HttpClient 的 execute 方法执行请求
CloseableHttpResponse response = httpClient.execute(httpGet);
// 获取请求状态
int code = response.getCode();
// 如果请求成功
if(code == HttpStatus.SC_OK){
http://LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
}
HttpClient 中发送 JSON 数据可以使用 StringHttpEntity 类实现,如下所示:
// 请求参数
String url = "http://localhost:10010/user/body";
// 创建 GET 请求对象
HttpPost httpPost = new HttpPost(url);
// 构建对象
User user = new User();
user.setName("张三")
.setAge(20)
.setAddress(new Address()
.setCounty("中国")
.setCity("北京"))
.setAihao(Arrays.asList("跑步", "爬山", "看书"));
// 创建 字符串实体对象
HttpEntity httpEntity = new StringEntity(JSON.toJSONString(user));
httpPost.setEntity(httpEntity);
// 发送 POST 请求
httpClient.execute(httpPost);
// 修改 contentType
// 创建 ContentType 对象为 form 表单模式
ContentType contentType = ContentType.create("application/x-www-form-urlencoded", StandardCharsets.UTF_8);
// 添加到 HttpPost 头中
httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType);
创建请求数据 HttpEntity
// 方式一、自己拼接请求数据,并且创建 StringEntity 对象
String query = "name="+ URLEncoder.encode("张三", "utf-8") +"&age=20";
HttpEntity httpEntity = new StringEntity(query);
// 方式二、通过UrlEncodedFormEntity 创建 HttpEntity
HttpEntity httpEntity = new UrlEncodedFormEntity(
Arrays.asList(new BasicNameValuePair("name", "张三"),
new BasicNameValuePair("age", "20")),
StandardCharsets.UTF_8
);
// 把 HttpEntity 设置到 HttpPost 中
httpPost.setEntity(httpEntity);
//要上传的文件
File file = new File("F:/20150703212056_Yxi4L.jpeg");
// 创建对象
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
// 添加二进制消息体
builder.addBinaryBody("file", file);
// 也可以添加文本消息
ContentType contentType = ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8);
builder.addTextBody("name", "张三", contentType);
// 通过 MultipartEntityBuilder 构建消息体
HttpEntity httpEntity = builder.build();
HttpPost httpPost = new HttpPost("http://localhost:10010/user/upload");
httpPost.setEntity(httpEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
// 获取请求状态
int code = response.getCode();
// 如果请求成功
if(code == HttpStatus.SC_OK){
LOGGER.info("响应结果为:{}", EntityUtils.toString(response.getEntity()));
}
// 请求下载路径
HttpGet httpGet = new HttpGet("http://localhost:10010/user/downLoad");
CloseableHttpResponse response = httpClient.execute(httpGet);
// 如果请求成功
if (response.getCode() == HttpStatus.SC_OK){
// 获取下载文件的文件名,此处的 File-Name 头信息,需要在服务端进行自定义
Header header = response.getFirstHeader("File-Name");
String value = header.getValue();
// 读取数据
byte[] bytes = EntityUtils.toByteArray(response.getEntity());
try (OutputStream outputStream = new FileOutputStream("F:/" + value);){
outputStream.write(bytes);
outputStream.flush();
}
}
// 转换为字符串
EntityUtils.toString(response.getEntity());
// 转换为字节数组
EntityUtils.toByteArray(response.getEntity());
@Data
@Accessors(chain = true)
class Response {
// 响应状态
private int code;
// 响应描述
private String msg;
// 响应体
private String body;
}
// 调用 execute 时自定义 响应处理类
Response execute = httpClient.execute(httpGet, response -> {
return new Response().setCode(response.getCode())
.setMsg(response.getReasonPhrase())
.setBody(EntityUtils.toString(response.getEntity(),
StandardCharsets.UTF_8));
});
// 创建 HttpClientContext对象
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute("name", "zhangsan");
HttpClientContext httpClientContext = HttpClientContext.adapt(httpContext);
// 登录
httpClient.execute(new HttpPost(""), httpClientContext);
// 获取数据
httpClient.execute(new HttpGet(""), httpClientContext);
具有低内存占有和出色的性能
引入依赖
com.squareup.okhttp3
okhttp
4.0.0
Java 自带的一个 HTTP 客户端工具
示例:
@Test
public void doGet() throws IOException {
String userId = "张三"; // 参数值
userId = URLEncoder.encode(userId, "UTF-8"); // 对参数值进行URL编码
//步骤一:创建URL对象
URL url = new URL("http://127.0.0.1:8094/masterdata/sysUser/getSysUserById?userId=" + userId);
//步骤二:打开连接 HttpURLConnection继承自URLConnection,是它的一个子类,
//而HttpURLConnection专门用于处理HTTP协议的连接,如果需要处理其他协议使用通用的URLConnection。
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//步骤三:设置请求方式
conn.setRequestMethod("GET");
//步骤四:读取响应内容
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
System.out.println(sb.toString());
}
@Test
public void doPost() throws IOException {
//创建URL对象
URL url = new URL("http://127.0.0.1:8094/masterdata/sysUser/saveUser");
//打开连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置请求方式
conn.setRequestMethod("POST");
// 设置请求头
conn.setRequestProperty("Content-Type", "application/json");
//启用输出流
//告诉连接对象您将使用输出流来发送数据,这样它会准备好接受输出流,并将数据发送到服务器。
//这是发送POST请求体数据所必需的步骤。get没有请求体不需要
conn.setDoOutput(true);
//设置请求体数据
Map map = new HashMap<>();
map.put("name", "张三");
String requestBody = JSON.toJSONString(map);
//发送请求体数据
try (DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream())) {
outputStream.write(requestBody.getBytes(StandardCharsets.UTF_8));
}
//读取响应内容
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
System.out.println(sb.toString());
}
引入依赖
org.springframework.cloud
spring-cloud-starter-openfeign
在 spring boot 启动类加上@EnableFeignClients注解
// name:指定Feign的名称,如果使用了注册中心,name属性会作为微服务的名称,用于服务发现
// url:Feign调用的跳转路径,可以在配置文件中设置,多用于代码调试
@FeignClient(name = "masterdata",url = "${masterdata-service-url}")
public interface ISysUserClient {
@GetMapping(value = "/masterdata/getSysUserById")
public Map getSysUserById(@RequestParam("userId") String userId);
}
默认是连接超时10s,读超时60s ,feign 集成了 ribbon 和 hystrix,feign 本身不带超时限制,其超时是由 ribbon 和 hystrix 控制的。
## 方法一:设置在ribbon上
ribbon:
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,默认false
ReadTimeout: 5000 #负载均衡超时时间,默认值5000
ConnectTimeout: 3000 #ribbon请求连接的超时时间,默认值2000
MaxAutoRetries: 0 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 1 #对切换实例的重试次数,默认1
## 方法二:设置在feign client上
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 3000
AsyncHttpClient是一个独立的开源库,它不依赖于任何的框架或者技术栈
依赖:
org.asynchttpclient
async-http-client
2.12.3
示例:
public class TestAsyncHttpClient {
@Test
public void doGet() throws IOException {
try (AsyncHttpClient client = new DefaultAsyncHttpClient();) {
BoundRequestBuilder requestBuilder = client.prepareGet("http://127.0.0.1:8094/masterdata/sysUser/getSysUserById?userId=郭郭");
CompletableFuture future = requestBuilder.execute()
.toCompletableFuture()
.thenApply(Response::getResponseBody);
//使用join等待响应完成
String responseBody = future.join();
System.out.println(responseBody);
}
}
@Test
public void doPost() throws IOException {
try (AsyncHttpClient client = new DefaultAsyncHttpClient();) {
BoundRequestBuilder requestBuilder = client.preparePost("http://127.0.0.1:8094/masterdata/sysUser/saveUser");
//requestBody请求入参
Map map = new HashMap<>();
map.put("name", "郭郭");
String requestBody = JSON.toJSONString(map);
requestBuilder.addHeader("Content-Type", "application/json");
requestBuilder.setBody(requestBody);
CompletableFuture future = requestBuilder.execute()
.toCompletableFuture()
.thenApply(Response::getResponseBody);
//使用join等待响应完成
String responseBody = future.join();
System.out.println(responseBody);
}
}
}