您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

Java调用外部REST请求的几种方式

时间:2021-08-19 12:03:12  来源:  作者:十二又十三

1 restTemplate — spring 提供

特点:

1、RestOperations 提供了各种封装方法,非常方便直接将返回转成实体类。

2、默认使用JDK 的HttpURLConnection进行通信,但是可以通过RestTemplate.setRequestFactory 切换到不同的HTTP源:如Apache HttpComponents、Netty、OkHttp。

3、支持同步、异步请求;

4、支持更多的定制,比如拦截器等。

ps:支持 get 请求,参数是 body 的形式。

参考:https://www.huaweicloud.com/articles/7f32ca1acff12162ce8d3bace872ae04.html

国外知名博客Baeldung的博客 The Guide to RestTemplate: https://www.baeldung.com/rest-template

1.1 底层是JAVA的HttpURLConnection(默认使用,可以定制)

所有的请求都需要执行 doExecute() 方法

@Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
    Assert.notNull(url, "URI is required");
    Assert.notNull(method, "HttpMethod is required");
    ClientHttpResponse response = null;

    Object var14;
    try {
        // 创建请求
        ClientHttpRequest request = this.createRequest(url, method);
        if (requestCallback != null) {
            requestCallback.doWithRequest(request);
        }

        response = request.execute();
        this.handleResponse(url, method, response);
        var14 = responseExtractor != null ? responseExtractor.extractData(response) : null;
    } catch (IOException var12) {
        String resource = url.toString();
        String query = url.getRawQuery();
        resource = query != null ? resource.substring(0, resource.indexOf(63)) : resource;
        throw new ResourceAccessException("I/O error on " + method.name() + " request for "" + resource + "": " + var12.getMessage(), var12);
    } finally {
        if (response != null) {
            response.close();
        }

    }

    return var14;
}

HttpAccessor 创建请求

public abstract class HttpAccessor {
    ... // 省略代码无数
    protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
        // 使用 ClientHttpRequestFactory 创建请求
        ClientHttpRequest request = this.getRequestFactory().createRequest(url, method);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("HTTP " + method.name() + " " + url);
        }

        return request;
    }
}

ClientHttpRequestFactory接口的具体实现,如:SimpleClientHttpRequestFactory 创建请求

public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
    // 使用 HttpURLConnection 创建请求
    HttpURLConnection connection = this.openConnection(uri.toURL(), this.proxy);
    this.prepareConnection(connection, httpMethod.name());
    return (ClientHttpRequest)(this.bufferRequestBody ? new SimpleBufferingClientHttpRequest(connection, this.outputStreaming) : new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming));
}

1.2 post 请求,返回直接封装为实体

RestTemplate restTemplate = new RestTemplate();
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class);
assertThat(foo, notNullValue());
assertThat(foo.getName(), is("bar"));

1.3 get请求,但是参数是body形式

一般 get 请求,不支持 body 传参。

参考:https://stackoverflow.com/questions/43421126/how-to-use-httpclient-to-send-content-in-body-of-get-request/68812976#68812976

HTTP GET with a body is a somewhat unconventional construct that falls in a gray area of the HTTP specification - the end result is that many older pieces of software either cannot handle such a request at all, or will explicitly reject it because they believe it to be malformed.

带有body参数的HTTP GET是一种非传统的构造,属于HTTP规范的灰色区域。最终的结果是,许多旧的软件要么根本不能处理这样的请求,要么会明确拒绝,因为他们认为它是格式错误的请求。

/**
 * 注意:get请求,但是参数是body形式
 *
 * @param url
 * @param paramBody
 * @return
 */
private String getWithBody(String url, Map<String, Object> paramBody) {
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setContentType(MediaType.AppLICATION_JSON);
    httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    HttpEntity requestEntity = new HttpEntity(JsonUtil.of(paramBody), httpHeaders);
    RestTemplate template = getTemplate();
    ResponseEntity response = template.exchange(url, HttpMethod.GET, requestEntity, String.class);
    Object result = response.getBody();
    logger.info("/invokeThirdPartyRequest/getWithBody/result/[{}]", result.toString());
    return result.toString();
}
/**
 * 获取 RestTemplate
 *
 * @return
 */
private RestTemplate getTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    //修改restTemplate的RequestFactory使其支持Get携带body参数
    restTemplate.setRequestFactory(new HttpComponentsClientRestfulHttpRequestFactory());
    return restTemplate;
}

import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

import java.net.URI;

public class HttpComponentsClientRestfulHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {

    @Override
    protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
        if (httpMethod == HttpMethod.GET) {
            return new HttpGetRequestWithEntity(uri);
        }
        return super.createHttpUriRequest(httpMethod, uri);
    }

    /**
     * 定义HttpGetRequestWithEntity实现HttpEntityEnclosingRequestBase抽象类,以支持GET请求携带body数据
     */
    private static final class HttpGetRequestWithEntity extends HttpEntityEnclosingRequestBase {
        public HttpGetRequestWithEntity(final URI uri) {
            super.setURI(uri);
        }
        @Override
        public String getMethod() {
            return HttpMethod.GET.name();
        }
    }
}

2 HttpUtil — hutool 提供

HttpUtil 其实是 HttpRequest 的封装。

它支持各种封装好的get、post、put请求。

2.1 get 请求

public static String get(String urlString, Charset customCharset) {
    return ((HttpRequest)HttpRequest.get(urlString).charset(customCharset)).execute().body();
}

public static String get(String urlString) {
    return get(urlString, HttpGlobalConfig.timeout);
}

public static String get(String urlString, int timeout) {
    return HttpRequest.get(urlString).timeout(timeout).execute().body();
}

// form 表单格式的入参
public static String get(String urlString, Map<String, Object> paramMap) {
    return HttpRequest.get(urlString).form(paramMap).execute().body();
}

// form 表单格式的入参,并设置超时时间
public static String get(String urlString, Map<String, Object> paramMap, int timeout) {
    return HttpRequest.get(urlString).form(paramMap).timeout(timeout).execute().body();
}

2.2 post 请求

这些请求最终调用的都是 HttpRequest 的 execute() 方法。

// form 表单格式的入参
public static String post(String urlString, Map<String, Object> paramMap) {
    return post(urlString, paramMap, HttpGlobalConfig.timeout);
}

// form 表单格式的入参,并设置超时时间
public static String post(String urlString, Map<String, Object> paramMap, int timeout) {
    return HttpRequest.post(urlString).form(paramMap).timeout(timeout).execute().body();
}

// body 格式入参
public static String post(String urlString, String body) {
    return post(urlString, body, HttpGlobalConfig.timeout);
}

// body 格式入参,并设置超时时间
public static String post(String urlString, String body, int timeout) {
    return HttpRequest.post(urlString).timeout(timeout).body(body).execute().body();
}

2.3 一个例子

Map<String, Object> param = new HashMap<>();
param.put("userId", userId);
String res = HttpUtil.post(url, JsonUtil.of(param));

3 HttpRequest — hutool 提供

HttpRequest 提供了非常方便构造请求的构造函数。当参数比较多、header比较多的时候,可以使用这种方式。(这里使用了构造模式)

3.1 底层是Java的HttpURLConnection

HttpRequest 底层又是使用了 java 提供的 HttpURLConnection

上源码:

最终都需要执行这个execute方法,这个方法调用了hutool封装的HttpConnection,这个HttpConnection又使用了java提供的HttpURLConnection。

// hutool 执行方法
public HttpResponse execute(boolean isAsync) {
    this.urlWithParamIfGet();
    this.initConnection();
    this.send();
    HttpResponse httpResponse = this.sendRedirectIfPossible();
    if (null == httpResponse) {
        httpResponse = new HttpResponse(this.httpConnection, this.charset, isAsync, this.isIgnoreResponseBody());
    }

    return httpResponse;
}
public class HttpConnection {
    private final URL url;
    private final Proxy proxy;
    // 这个连接 HttpURLConnection ,是java提供的
    private HttpURLConnection conn;
    ...// 省略无数代码
}

3.2 一个例子

private String invoke(String url, String isMock, Map<String, Object> map) {
    String result = HttpRequest.post(url).body(JSONUtil.toJsonStr(map)).execute().body();
    return result;
}


Tags:REST请求   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
1 restTemplate &mdash; spring 提供特点:1、RestOperations 提供了各种封装方法,非常方便直接将返回转成实体类。2、默认使用JDK 的HttpURLConnection进行通信,但是可以通过Re...【详细内容】
2021-08-19  Tags: REST请求  点击:(83)  评论:(0)  加入收藏
▌简易百科推荐
一、Redis使用过程中一些小的注意点1、不要把Redis当成数据库来使用二、Arrays.asList常见失误需求:把数组转成list集合去处理。方法:Arrays.asList 或者 Java8的stream流式处...【详细内容】
2021-12-27  CF07    Tags:Java   点击:(3)  评论:(0)  加入收藏
文章目录 如何理解面向对象编程? JDK 和 JRE 有什么区别? 如何理解Java中封装,继承、多态特性? 如何理解Java中的字节码对象? 你是如何理解Java中的泛型的? 说说泛型应用...【详细内容】
2021-12-24  Java架构师之路    Tags:JAVA   点击:(5)  评论:(0)  加入收藏
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  小码匠和老码农    Tags:JVM调优   点击:(11)  评论:(0)  加入收藏
前言JDBC访问Postgresql的jsonb类型字段当然可以使用Postgresql jdbc驱动中提供的PGobject,但是这样在需要兼容多种数据库的系统开发中显得不那么通用,需要特殊处理。本文介绍...【详细内容】
2021-12-23  dingle    Tags:JDBC   点击:(12)  评论:(0)  加入收藏
Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试。目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的...【详细内容】
2021-12-23  JAVA小白    Tags:Java   点击:(10)  评论:(0)  加入收藏
Java从版本5开始,在 java.util.concurrent.locks包内给我们提供了除了synchronized关键字以外的几个新的锁功能的实现,ReentrantLock就是其中的一个。但是这并不意味着我们可...【详细内容】
2021-12-17  小西学JAVA    Tags:JAVA并发   点击:(10)  评论:(0)  加入收藏
一、概述final是Java关键字中最常见之一,表示“最终的,不可更改”之意,在Java中也正是这个意思。有final修饰的内容,就会变得与众不同,它们会变成终极存在,其内容成为固定的存在。...【详细内容】
2021-12-15  唯一浩哥    Tags:Java基础   点击:(14)  评论:(0)  加入收藏
1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友。2、解决方案这次其实是碰到了一个问题,一般的情况...【详细内容】
2021-12-15  软件老王    Tags:logback   点击:(17)  评论:(0)  加入收藏
本篇文章我们以AtomicInteger为例子,主要讲解下CAS(Compare And Swap)功能是如何在AtomicInteger中使用的,以及提供CAS功能的Unsafe对象。我们先从一个例子开始吧。假设现在我们...【详细内容】
2021-12-14  小西学JAVA    Tags:JAVA   点击:(21)  评论:(0)  加入收藏
一、概述观察者模式,又可以称之为发布-订阅模式,观察者,顾名思义,就是一个监听者,类似监听器的存在,一旦被观察/监听的目标发生的情况,就会被监听者发现,这么想来目标发生情况到观察...【详细内容】
2021-12-13  唯一浩哥    Tags:Java   点击:(16)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条