SpringCloud學習之-使用RestTemplate發送http請求

上一節咱們學習瞭如何使用jdk的URI工具類發送http請求,這一節學習一下spring框架中對於jdk的網絡請求工具類的封裝RestTemplate.spring

@RestController
public class Controller {

    @GetMapping("hello")
    public String hello(){
        return "hello";
    }
}
複製代碼

首先仍是接着上一節的內容。先建立一個服務端,提供上述接口。json

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

接着使用RestTemplate來調用該服務。能夠看出,代碼量上,節省了很是多。那麼RestTemplate到底進行了哪些封裝呢?咱們從源碼來探究一下。bash

在這兒我就以基礎的getForObject方法來進行分析。網絡

String url, Class<T> responseType, Object... uriVariables
複製代碼

getForObject方法有三個參數app

參數名 做用
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方法post

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/helloui

下面進入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轉對象了吧。


返回目錄

相關文章
相關標籤/搜索