目前Spring RestTemplate是常用的http请求工具类,本文简单Spring RestTemplate的请求过程。
接下来以ResponseEntity exchange(String url, HttpMethod method, @Nullable HttpEntity> requestEntity,
ParameterizedTypeReference responseType, Object… uriVariables)方法为起点,揭开http请求过程。
public ResponseEntity exchange(String url, HttpMethod method, @Nullable HttpEntity> requestEntity,ParameterizedTypeReference responseType, Object... uriVariables) throws RestClientException {Type type = responseType.getType();RequestCallback requestCallback = httpEntityCallback(requestEntity, type);ResponseExtractor> responseExtractor = responseEntityExtractor(type);return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
}
http的整体流程如下所示,首先创建httpRequest,其次处理httpRequest,最重要就是执行http请求,最后就是处理http响应。
protected T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor responseExtractor) throws RestClientException {Assert.notNull(url, "URI is required");Assert.notNull(method, "HttpMethod is required");ClientHttpResponse response = null;try {// 创建httpRequestClientHttpRequest request = createRequest(url, method);if (requestCallback != null) {// HttpEntityRequestCallback#doWithRequestrequestCallback.doWithRequest(request);}// http执行response = request.execute();// http响应处理handleResponse(url, method, response);return (responseExtractor != null ? responseExtractor.extractData(response) : null);}catch (IOException ex) {String resource = url.toString();String query = url.getRawQuery();resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);throw new ResourceAccessException("I/O error on " + method.name() +" request for \"" + resource + "\": " + ex.getMessage(), ex);}finally {if (response != null) {// 关闭流response.close();}}
}
Restemplate继承了InterceptingHttpAccessor,使用的是InterceptingClientHttpRequestFactory创建httpRequest。
public ClientHttpRequestFactory getRequestFactory() {// ClientHttpRequestInterceptor 支持拓展List interceptors = getInterceptors();if (!CollectionUtils.isEmpty(interceptors)) {ClientHttpRequestFactory factory = this.interceptingRequestFactory;if (factory == null) {// 创建默认的HttpRequestFactoryfactory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);this.interceptingRequestFactory = factory;}return factory;}else {return super.getRequestFactory();}
}
protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
}
调用HttpEntityRequestCallback的doWithRequest,若body为null,主要是设置header。若body补位null,则主要是通过根据body的类型匹配HttpMessageConverter,将body序列化为httpRequest中
public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {// 调用父类的doWithRequest方法super.doWithRequest(httpRequest);Object requestBody = this.requestEntity.getBody();if (requestBody == null) {HttpHeaders httpHeaders = httpRequest.getHeaders();HttpHeaders requestHeaders = this.requestEntity.getHeaders();// 将HttpEntity中的header复制到httpRequest中if (!requestHeaders.isEmpty()) {requestHeaders.forEach((key, values) -> httpHeaders.put(key, new ArrayList<>(values)));}// 设置ContentLengthif (httpHeaders.getContentLength() < 0) {httpHeaders.setContentLength(0L);}}else {Class> requestBodyClass = requestBody.getClass();Type requestBodyType = (this.requestEntity instanceof RequestEntity ?((RequestEntity>)this.requestEntity).getType() : requestBodyClass);HttpHeaders httpHeaders = httpRequest.getHeaders();HttpHeaders requestHeaders = this.requestEntity.getHeaders();MediaType requestContentType = requestHeaders.getContentType();// getMessageConverters()中的MessageConverters是在RestTemplate构造函数中添加的for (HttpMessageConverter> messageConverter : getMessageConverters()) {// 依次轮询每个messageConverter判断是否支持写当前httpRequestBodyif (messageConverter instanceof GenericHttpMessageConverter) {GenericHttpMessageConverter
前面说到默认创建的是InterceptingClientHttpRequest,接下来看看InterceptingClientHttpRequest的继承关系如下:
实际执行http请求就是executeInternal,但是从InterceptingClientHttpRequest的名字可以看出来,这个httpRequest实际上是一个调用链模式,可以根据需要拓展不同的HttpRequest,实现不同的功能,如常用的LoadBalancerInterceptor,也就是利用这个拓展能力实现LoadBalancer。
@Override
protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();return requestExecution.execute(this, bufferedOutput);
}private class InterceptingRequestExecution implements ClientHttpRequestExecution {private final Iterator iterator;public InterceptingRequestExecution() {this.iterator = interceptors.iterator();}@Overridepublic ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {if (this.iterator.hasNext()) {// 调用链依次调用ClientHttpRequestInterceptorClientHttpRequestInterceptor nextInterceptor = this.iterator.next();return nextInterceptor.intercept(request, body, this);}else {HttpMethod method = request.getMethod();Assert.state(method != null, "No standard HTTP method");// 创建最终执行http请求的ClientHttpRequest,factory默认为SimpleClientHttpRequestFactory,创建SimpleBufferingClientHttpRequestClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);// header全部复制request.getHeaders().forEach((key, value) -> delegate.getHeaders().addAll(key, value));// body复制if (body.length > 0) {if (delegate instanceof StreamingHttpOutputMessage) {StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;streamingOutputMessage.setBody(outputStream -> StreamUtils.copy(body, outputStream));}else {StreamUtils.copy(body, delegate.getBody());}}// 最终http请求return delegate.execute();}}
}
SimpleBufferingClientHttpRequest的继承关系
SimpleBufferingClientHttpRequest实际执行方法
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {// 复制header,是否全部复制由系统参数sun.net.http.allowRestrictedHeaders决定// connection 为HttpURLConnectionaddHeaders(this.connection, headers);// JDK <1.8 doesn't support getOutputStream with HTTP DELETEif (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {this.connection.setDoOutput(false);}if (this.connection.getDoOutput() && this.outputStreaming) {this.connection.setFixedLengthStreamingMode(bufferedOutput.length);}// http连接服务端this.connection.connect();if (this.connection.getDoOutput()) {// 若有body则发送整个请求,并获取请求结果FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());}else {// 发送http请求this.connection.getResponseCode();}return new SimpleClientHttpResponse(this.connection);
}
首先调用handleResponse处理异常情况,再调用ResponseEntityResponseExtractor中的HttpMessageConverterExtractor对响应进行装换。
protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {ResponseErrorHandler errorHandler = getErrorHandler();boolean hasError = errorHandler.hasError(response);if (logger.isDebugEnabled()) {try {int code = response.getRawStatusCode();HttpStatus status = HttpStatus.resolve(code);logger.debug("Response " + (status != null ? status : code));}catch (IOException ex) {// ignore}}if (hasError) {errorHandler.handleError(url, method, response);}
}private class ResponseEntityResponseExtractor implements ResponseExtractor> {@Nullableprivate final HttpMessageConverterExtractor delegate;public ResponseEntityResponseExtractor(@Nullable Type responseType) {if (responseType != null && Void.class != responseType) {this.delegate = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);}else {this.delegate = null;}}@Overridepublic ResponseEntity extractData(ClientHttpResponse response) throws IOException {if (this.delegate != null) {T body = this.delegate.extractData(response);return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(body);}else {return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).build();}}
}
public T extractData(ClientHttpResponse response) throws IOException {MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {return null;}MediaType contentType = getContentType(responseWrapper);try {for (HttpMessageConverter> messageConverter : this.messageConverters) {if (messageConverter instanceof GenericHttpMessageConverter) {GenericHttpMessageConverter> genericMessageConverter =(GenericHttpMessageConverter>) messageConverter;if (genericMessageConverter.canRead(this.responseType, null, contentType)) {if (logger.isDebugEnabled()) {ResolvableType resolvableType = ResolvableType.forType(this.responseType);logger.debug("Reading to [" + resolvableType + "]");}return (T) genericMessageConverter.read(this.responseType, null, responseWrapper);}}if (this.responseClass != null) {if (messageConverter.canRead(this.responseClass, contentType)) {if (logger.isDebugEnabled()) {String className = this.responseClass.getName();logger.debug("Reading to [" + className + "] as \"" + contentType + "\"");}return (T) messageConverter.read((Class) this.responseClass, responseWrapper);}}}}catch (IOException | HttpMessageNotReadableException ex) {throw new RestClientException("Error while extracting response for type [" +this.responseType + "] and content type [" + contentType + "]", ex);}throw new UnknownContentTypeException(this.responseType, contentType,responseWrapper.getRawStatusCode(), responseWrapper.getStatusText(),responseWrapper.getHeaders(), getResponseBody(responseWrapper));}