SpringCloud learning - using RestTemplate send http request

On a jdk we learned how to use the tools to send http request URI, this section to learn about spring framework for network requests jdk package RestTemplate tool class.

@RestController
public class Controller {

    @GetMapping("hello")
    public String hello(){
        return "hello";
    }
}
复制代码

Above all, then the contents of one. Create a server, providing the above interface.

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

RestTemplate then used to invoke the service. As can be seen, the amount of code, saving a lot. So RestTemplate in the end was what package it? We from source to explore it.

Here I will take getForObject based method for analysis.

String url, Class<T> responseType, Object... uriVariables
复制代码

The method has three parameters getForObject

parameter name effect
url Address requests
responseType Return type
uriVariables url inside padding field

Entry method

	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);
	}
复制代码

There are three lines in this method, the first row of a package AcceptHeaderRequestCallback object encapsulates a second row HttpMessageConverterExtractor objects, we can effect both the object put off, and then the third row is the execution request.

So we enter the execute method

	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);
	}
复制代码

In the excute method first made preparations, our string url converted into URI object. This object is what we on target to send an http request. There is a method expand when extended, the effect of the method is as follows

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

We use in the url {} enter a placeholder name, and it uriVariables in this map, we set the value of name hello, after this method, http://127.0.0.1:8080/{name} will become http://127.0.0.1:8080/hello .

DoExecute enter the following methods.

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);
	}
复制代码

Exception handling in addition to the relevant code, doExecute as the main code. The main logic still can be seen very clearly.

First create objects 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 and prepareConnection two ways to look at yourself and see and call our own on a URI object any difference.

Next, request a callback object processing

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);
	}
}
复制代码

Callback method of treatment get only one thing, it is to set the request header "Accept" attribute.

Request execution 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);
	}
复制代码

Processing returns results

Finally, the processing of the results, in fact, guess would have guessed, is the return flow of information into a package we can directly manipulate objects, generally the most commonly used objects should be the json turn right.


Back to Contents

Guess you like

Origin juejin.im/post/5cff89636fb9a07ef819f425