3

1 restTemplate — Spring provided

Features:

1. RestOperations provides a variety of encapsulation methods, which is very convenient to directly convert the return into an entity class.

2. By default, JDK's HttpURLConnection is used for communication, but you can switch to different HTTP sources through RestTemplate.setRequestFactory: such as Apache HttpComponents, Netty, OkHttp.

3. Support synchronous and asynchronous requests;

4. Support more customization, such as interceptors, etc.

ps: Support get request, the parameter is in the form of body.

Reference: https://www.huaweicloud.com/articles/7f32ca1acff12162ce8d3bace872ae04.html

Baeldung's blog The Guide to RestTemplate: https://www.baeldung.com/rest-template

1.1 The bottom layer is java's HttpURLConnection (used by default and can be customized)

All requests need to execute the doExecute() method

@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 create request

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;
    }
}

The specific implementation of the ClientHttpRequestFactory interface, such as: SimpleClientHttpRequestFactory to create a request

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 request, return directly encapsulated as entity

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 request, but the parameter is in the form of body

General get requests do not support body parameter passing.

Reference: 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.

HTTP GET with body parameters is a non-traditional structure, which belongs to the gray area of the HTTP specification. The end result is that many old software either can't handle such a request at all, or will explicitly reject it because they think it is a malformed request.

/**
 * 注意: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 — provided by hutool

HttpUtil is actually a package of HttpRequest.

It supports various encapsulated get, post, and put requests.

2.1 get request

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 request

These requests ultimately call the execute() method of HttpRequest.

// 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 An example

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

3 HttpRequest — provided by hutool

HttpRequest provides a very convenient constructor for constructing requests. This method can be used when there are more parameters and more headers. (The construction mode is used here)

3.1 The bottom layer is Java's HttpURLConnection

The bottom layer of HttpRequest uses HttpURLConnection

On the source code:

In the end, the execute method needs to be executed. This method calls the HttpConnection encapsulated HttpURLConnection . HttpConnection uses the 0611cda3080c80 provided by java.

// 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 An example

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

程序员伍六七
201 声望597 粉丝