专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

SpringCloud学习之-使用RestTemplate发送http请求

上一节我们学习了如何使用jdk的URI工具类发送http请求,这一节学习一下spring框架中对于jdk的网络请求工具类的封装RestTemplate.

@RestController
public class Controller {

    @GetMapping("hello")
    public String hello(){
        return "hello";
    }
}

首先还是接着上一节的内容。先创建一个服务端,提供上述接口。

template.getForObject("http://127.0.0.1:8763/hello",String.class);

接着使用RestTemplate来调用该服务。可以看出,代码量上,节省了非常多。那么RestTemplate到底进行了哪些封装呢?我们从源码来探究一下。

在这儿我就以基础的getForObject方法来进行分析。

String url, Class<T> responseType, Object... uriVariables

getForObject方法有三个参数

参数名 作用
url 请求的地址
responseType 返回值的类型
uriVariables url里面的填充字段

进入方法

    public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
        HttpMessageConverterExtractor<T> responseExtractor =
                new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
        return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
    }

在该方法中有三行代码,第一行封装了一个AcceptHeaderRequestCallback对象,第二行封装了一个HttpMessageConverterExtractor对象,这两对象的作用我们可以先放一放,然后第三行就是执行请求。

所以我们进入execute方法

    public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
            @Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables)
            throws RestClientException {

        URI expanded = getUriTemplateHandler().expand(url, uriVariables);
        return doExecute(expanded, method, requestCallback, responseExtractor);
    }

在excute方法中首先做了准备工作,将我们的字符串url转化成了URI对象。这个对象正是我们上一节用以发送http请求的对象。在扩展的时候有一个expand方法,该方法的作用大致如下

    Map<String,String> uriVariables = new HashMap<>();
    uriVariables.put("name" ,"hello");
    template.getForObject("http://127.0.0.1:8080/{name}",String.class,uriVariables);

在url中我们使用{}输入了一个占位符name,而在uriVariables这个map中我们设置了name的值为hello,经过这个方法后,http://127.0.0.1:8080/{name} 就会变成 http://127.0.0.1:8080/hello

下面进入doExecute方法。

ClientHttpResponse response = null;
    try {
        //封装一个request对象
        ClientHttpRequest request = createRequest(url, method);
        if (requestCallback != null) {
        //对request对象进行回调处理
            requestCallback.doWithRequest(request);
        }
        //执行request请求
        response = request.execute();
        //处理返回结果
        handleResponse(url, method, response);
        return (responseExtractor != null ? responseExtractor.extractData(response) : null);
    }

除开异常处理相关代码,doExecute主要代码如上。可以看出主要逻辑还是很清晰的。

首先创建ClientHttpRequest对象

    protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
        ClientHttpRequest request = getRequestFactory().createRequest(url, method);
        if (logger.isDebugEnabled()) {
            logger.debug("HTTP " + method.name() + " " + url);
        }
        return request;
    }

    public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
        HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
        prepareConnection(connection, httpMethod.name());

        if (this.bufferRequestBody) {
            return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
        }
        else {
            return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
        }
    }

openConnection和prepareConnection这两个方法可以自己看下,看看和上一节我们自己调用URI对象有啥区别。

接下来对request对象进行回调处理

public void doWithRequest(ClientHttpRequest request) throws IOException {
    if (this.responseType != null) {
        List<MediaType> allSupportedMediaTypes = getMessageConverters().stream()
                .filter(converter -> canReadResponse(this.responseType, converter))
                .flatMap(this::getSupportedMediaTypes)
                .distinct()
                .sorted(MediaType.SPECIFICITY_COMPARATOR)
                .collect(Collectors.toList());
        if (logger.isDebugEnabled()) {
            logger.debug("Accept=" + allSupportedMediaTypes);
        }
        request.getHeaders().setAccept(allSupportedMediaTypes);
    }
}

get方法的回调处理只做了一件事,就是设置请求头的”Accept”属性。

执行request请求

    public final ClientHttpResponse execute() throws IOException {
        //校验,确认请求未执行过
        assertNotExecuted();
        ClientHttpResponse result = executeInternal(this.headers);
        //执行完成,修改请求状态
        this.executed = true;
        return result;
    }

    protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
        byte[] bytes = this.bufferedOutput.toByteArray();
        if (headers.getContentLength() < 0) {
            //设置请求头属性
            headers.setContentLength(bytes.length);
        }
        ClientHttpResponse result = executeInternal(headers, bytes);
        this.bufferedOutput = new ByteArrayOutputStream(0);
        return result;
    }

    protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        //将我们设置的请求头加入connection中
        addHeaders(this.connection, headers);
        if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
            this.connection.setDoOutput(false);
        }
        if (this.connection.getDoOutput() && this.outputStreaming) {
            this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
        }
        //建立连接,发送请求
        this.connection.connect();
        if (this.connection.getDoOutput()) {
            FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
        }
        else {
            this.connection.getResponseCode();
        }
        return new SimpleClientHttpResponse(this.connection);
    }

处理返回结果

最后对结果的处理,其实猜也能猜到了,就是将返回的信息流封装成我们可以直接操作的对象,一般最常用的应该就是json转对象了吧。


返回目录

文章永久链接:https://tech.souyunku.com/19154

未经允许不得转载:搜云库技术团队 » SpringCloud学习之-使用RestTemplate发送http请求

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们