首页 > 解决方案 > spring integraion outbound gateway 的动态 https URL 有问题

问题描述

我想建立一个软网关,所以我会为我的内部系统提供一些spring集成的url,然后我的系统会发送到真实目的地的url。这是我的代码。这是一个出站网关,我在 inputchannel 标头中设置了 https url。

<int:channel id="inputChannel"/>
<int:channel id="outputChannel">
    <int:queue capacity="100"/>
</int:channel>

<int-http:outbound-gateway   request-channel="inputChannel"
                            url-expression="headers.dynamicUrl"
                           http-method-expression="POST"
                           expected-response-type="java.lang.String"
                            reply-channel="outputChannel"

                           charset="UTF-8">
</int-http:outbound-gateway>

我的java代码是这样的

MessageChannel inputChannel = context.getBean("inputChannel", MessageChannel.class);
    PollableChannel outputChannel = context.getBean("outputChannel", PollableChannel.class);
    inputChannel.send(msgWithHTTPsUrl);//msg with https Url https://www.example.net
    Message<?> replyMesg = outputChannel.receive();
    Message<?> toSend = MessageBuilder.withPayload(replyMesg.getPayload()).copyHeadersIfAbsent(replyMesg.getHeaders()).build();
    System.out.println(toSend);
    return toSend;

并且程序可以打印以发送消息。但浏览器无法得到回复。它说 ERR_CONTENT_DECODING_FAILED。也许https://www.example.net使用 gzip 压缩。那么我该如何处理这个,以便我可以为我公司的内部系统做一个软网关呢?谢谢你!


现在,我添加了一个 rest-template 来解决这个错误

<int-http:outbound-gateway   request-channel="inputChannel"
                        url-expression="headers.dynamicUrl"
                       http-method-expression="POST"
                       expected-response-type="java.lang.String"
                        reply-channel="outputChannel"
                        rest-template="restTemplate"
                       charset="UTF-8">

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg ref="sslFactory" />
</bean>
<bean id="sslFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
    <constructor-arg ref="httpClient"/>
</bean>

我设置了忽略服务器端证书的验证,这是我的 httpclient 的 java 代码

        @Component("httpClient")
    public class HttpClientFactory extends AbstractFactoryBean<HttpClient> {

        @Override
        public Class<?> getObjectType() {
            return HttpClient.class;
        }
        public HttpClient getInstance() throws Exception {
            return createInstance();
        }
        @Override
        protected HttpClient createInstance() throws Exception {

            RequestConfig defaultRequestConfig = RequestConfig.custom()
                    .setSocketTimeout(3000)
                    .setConnectTimeout(3000)
                    .setConnectionRequestTimeout(3000)
                    .setStaleConnectionCheckEnabled(true)
                    .build();

            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            TrustStrategy allTrust = new TrustStrategy() {
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            };

            SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, allTrust).build();

            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
                    .setDefaultRequestConfig(defaultRequestConfig).build();
            return httpClient;
        }

但是当我使用这个httpclient时,outbund-gateway得到4xx/5xx响应,我写了一个HttpPost来测试这个httpclient,响应是可以的。我对 outbund-gateway 有什么误解吗?或者我还错过了什么?


我编写测试用例来测试我的 Spring 集成应用程序,以及我注入 Spring 集成的 httpclient。spring 集成应用程序得到错误回复:

org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://www.npr.org/]; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request, failedMessage=GenericMessage [payload=byte[0], headers={content-length=0, http_requestMethod=POST, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3afa4833, httpMethod=POST, replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3afa4833, respUrl=https://www.npr.org/, host=localhost:8080, http_requestUrl=http://localhost:8080/sihttp/mytest, connection=Keep-Alive, id=256ed96e-9c00-ecf4-9d1b-63f37635fb4a, contentType=application/json;charset=UTF-8, accept-encoding=gzip,deflate, user-agent=Apache-HttpClient/4.5.6 (Java/1.8.0_131), timestamp=1544368429831}]

并且httpClient直接访问https://www.npr.org/已经成功返回。测试代码是这样的:

CloseableHttpClient httpClient = HttpClients.createDefault(); // same httpclinet I inject in outbound gateway's rest-template
    HttpPost post=null;
    post = new HttpPost("http://localhost:8080/sihttp/mytest"); // this post will goto my spring integration app, in spring integration app, I will map this  url to https://www.npr.ogr, and send out in outbound gateway
//   post = new HttpPost("https://www.npr.org/"); // npr.org can successful visit in this post
        post.setHeader("Content-Type", "application/json;charset=UTF-8");
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(6000).setConnectionRequestTimeout(6000)
                .setSocketTimeout(6000).build();
        post.setConfig(requestConfig);
        CloseableHttpResponse httpResponse = httpClient.execute(post);
        HttpEntity httpEntity = httpResponse.getEntity();
        if (httpEntity != null) {
            System.out.println(EntityUtils.toString(httpEntity));
        }

        httpResponse.close();

在 spring 集成中,httpclient 使用 httpContext 执行

HttpResponse httpResponse = this.httpClient.execute(this.httpRequest, this.httpContext);

在 HttpClient 中,它直接执行。

httpClient.execute(post);

这是两个不同结果的原因吗?

标签: spring-integration

解决方案


如果故事是关于 GZIP 的,你应该考虑注入<int-http:outbound-gateway>不同的:

<xsd:attribute name="request-factory" type="xsd:string">
        <xsd:annotation>
            <xsd:documentation><![CDATA[
Reference to a ClientHttpRequestFactory to be used by the underlying RestTemplate.
                ]]></xsd:documentation>
            <xsd:appinfo>
                <tool:annotation kind="ref">
                    <tool:expected-type type="org.springframework.http.client.ClientHttpRequestFactory" />
                </tool:annotation>
            </xsd:appinfo>
        </xsd:annotation>
    </xsd:attribute>

我的建议是使用HttpComponentsClientHttpRequestFactory.

如果即使这样也没有帮助,请与我们分享整个堆栈跟踪以确定可能遗漏的内容。


推荐阅读