springboot http添加请求头 添加请求证书

首先明确两个事情:请求对象,连接对象

我们知道你要是想发起一个请求,需要指定两个环节内容,一个是请求内容对象(request),一个是连接内容对象(httpClient)
它们两个的作用我们在下面会看到

简要分析源码

1.先说一下结论,spring所有的核心代码都在doxxx()方法里面,而http请求的核心代码在doExecute()中。

# 我们平时会写这个一个方法去开启http请求调用
restTemplate.postForObject(url,httpEntity, xxx.class);

# 往里钻
@Nullable
    public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = this.httpEntityCallback(request, responseType);
        HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor(responseType, this.getMessageConverters(), this.logger);
        return this.execute(url, HttpMethod.POST, requestCallback, responseExtractor, (Object[])uriVariables);
    }

#继续钻,发现了doxxx()方法
@Nullable
    public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
        URI expanded = this.getUriTemplateHandler().expand(url, uriVariables);
        return this.doExecute(expanded, method, requestCallback, responseExtractor);
    }

#看看实现,我们会发现有一个创建request的操作
@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;
    }

# 我们发现所有的request对象都是通过factory创建的,不同的factory会创建不同的request对象
# 因为目前我们位于抽象类HttpAccessor中,所以我们要继续往实现类追踪getRequestFactory()方法
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
        ClientHttpRequest request = this.getRequestFactory().createRequest(url, method);
        this.initialize(request);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("HTTP " + method.name() + " " + url);
        }

        return request;
    }

# 此时我们位于InterceptingHttpAccessor抽象类中,继续往下追踪就是RestInterceptors类了,没有重写getRequestFactory()方法,所以我们要重点关注InterceptingHttpAccessor抽象类中的重写逻辑:
public ClientHttpRequestFactory getRequestFactory() {
        List<ClientHttpRequestInterceptor> interceptors = this.getInterceptors();
        if (!CollectionUtils.isEmpty(interceptors)) {
            ClientHttpRequestFactory factory = this.interceptingRequestFactory;
            if (factory == null) {
            	// 如果有interceptors,则融合父类的factory和interceptors,返回一个新的factory来覆盖原有父类factory
                factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
                this.interceptingRequestFactory = (ClientHttpRequestFactory)factory;
            }

            return (ClientHttpRequestFactory)factory;
        } else {
        	// 如果没有则interceptors,则直接用父类中的factory,
            return super.getRequestFactory();
        }
    }

至此,我们可以得到以下结论,如果想对原有请求进行扩展,我们需要从两个对象进行下手:factory,interceptor。

接下来我们看一下factory和interceptor两个类中都有什么内容:

#factory
public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {
	// 重点关注!!!连接对象
    private HttpClient httpClient;
    @Nullable
    private RequestConfig requestConfig;
    private boolean bufferRequestBody = true;
    @Nullable
    private BiFunction<HttpMethod, URI, HttpContext> httpContextFactory;
}

#interceptor
public interface ClientHttpRequestInterceptor {
	// 重点关注!!!request对象
    ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException;
}

我们可以发现在factory中我们可以对连接对象进行修改,在interceptor中可以对请求对象进行修改;我们回归下文章开头,一个请求的两个组成部分我们已经发现了。接下来就演示下不同场景应该怎么使用这两种对象。

场景1:添加固定请求头

分析:请求头内容属于请求对象,所以我们通过interceptor来实现

@Configuration
public class RestTemplateConfig {
    /**
     * restTemplate
     */
    @ConditionalOnMissingBean
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate();
        ClientHttpRequestInterceptor clientHttpRequestInterceptor = new ClientHttpRequestInterceptor() {
            @Override
            public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
                throws IOException {
                request.getHeaders().set("X-ID", "");
                request.getHeaders().set("X-APPKEY", "");
                return execution.execute(request, body);
            }
        };
        restTemplate.setInterceptors(Collections.singletonList(clientHttpRequestInterceptor));
        return restTemplate;
    }
}

场景二:添加请求证书

分析:请求头内容属于连接对象,所以我们通过factory来实现

public static HttpComponentsClientHttpRequestFactory generateHttpRequestFactory() {
        TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;
        SSLContext sslContext = null;
        try {
            sslContext = SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                // 增加请求证书
                .loadKeyMaterial(ks, keyStorePassword.toCharArray())
                .setProtocol("TLSv1.2")
                .build();
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            log.error("generateHttpRequestFactory failed:", e);
        }
        SSLConnectionSocketFactory connectionSocketFactory =
            new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());

        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.setSSLSocketFactory(connectionSocketFactory);
        CloseableHttpClient httpClient = httpClientBuilder.build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpClient);
        factory.setConnectTimeout(15000);
        factory.setReadTimeout(5000);
        return factory;
}

当然两者可以同时存在:

public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
		// 修改factory
        RestTemplate restTemplate = new RestTemplate(generateHttpRequestFactory());
        ClientHttpRequestInterceptor clientHttpRequestInterceptor = new ClientHttpRequestInterceptor() {
            @Override
            public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
                throws IOException {
                request.getHeaders().set("X-HW-ID", "com.huawei.osec");
                request.getHeaders().set("X-HW-APPKEY", "/D2QodV7Lu2EUk4D9HEUsQ==");
                return execution.execute(request, body);
            }
        };
        // 修改interceptor
        restTemplate.setInterceptors(Collections.singletonList(clientHttpRequestInterceptor));
        return restTemplate;
    }

你可能感兴趣的:(spring,boot,http,后端)