【问题标题】:Setting a custom HTTP header dynamically with Spring-WS client使用 Spring-WS 客户端动态设置自定义 HTTP 标头
【发布时间】:2011-03-11 07:11:57
【问题描述】:

使用 Spring-WS 时如何在客户端动态设置自定义 HTTP 标头(不是 SOAP 标头)?

【问题讨论】:

    标签: java spring http header spring-ws


    【解决方案1】:
    public class AddHttpHeaderInterceptor implements ClientInterceptor {
    
    public boolean handleFault(MessageContext messageContext)
            throws WebServiceClientException {
        return true;
    }
    
    public boolean handleRequest(MessageContext messageContext)
            throws WebServiceClientException {
         TransportContext context = TransportContextHolder.getTransportContext();
         HttpComponentsConnection connection =(HttpComponentsConnection) context.getConnection();
         connection.addRequestHeader("name", "suman");
    
        return true;
    }
    
    public boolean handleResponse(MessageContext messageContext)
            throws WebServiceClientException {
        return true;
    }
    
    }
    

    配置:

        <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
        ...
        <property name="interceptors">
            <list>
                <bean class="com.blah.AddHttpHeaderInterceptor" />
            </list>
        </property>
    </bean>
    

    【讨论】:

    • 好答案,对于未来的用户,使用 HttpComponentsConnection 代替 CommonsHttpConnection,因为它已被弃用。
    • 在运行 JUnit 测试时是否有效?就我而言,它不是因为context.getConnection() 返回MockSenderConnection。我正在使用MockWebServiceServer 进行单元测试。
    • 最好扩展ClientInterceptorAdapter
    • 更好的是,检查connection 是否是HeadersAwareSenderWebServiceConnection 的实例,以防使用不同的传输方式。
    【解决方案2】:

    ClientInterceptor 非常适合静态标头值。但是当每个请求都应该应用不同的值时,就不可能使用它。在那种情况下WebServiceMessageCallback 很有帮助:

    final String dynamicParameter = //...
    
    webServiceOperations.marshalSendAndReceive(request, 
        new WebServiceMessageCallback() {
            void doWithMessage(WebServiceMessage message) {
                TransportContext context = TransportContextHolder.getTransportContext();
                CommonsHttpConnection connection = (CommonsHttpConnection) context.getConnection();
                PostMethod postMethod = connection.getPostMethod();
                postMethod.addRequestHeader( "fsreqid", dynamicParameter );
            }
    }
    

    【讨论】:

    • 这个方案比使用客户端拦截器更灵活。恕我直言,它应该是首选。
    • 我收到以下异常 java.lang.ClassCastException: 在这一行 context.getConnection() org.springframework.ws.transport.http.HttpServletConnection 不能转换为 org.springframework.ws.transport .http.CommonsHttpConnection
    • 仅供参考,org.springframework.ws.transport.http.CommonsHttpConnection 已被弃用,取而代之的是 org.springframework.ws.transport.http.HttpComponentsConnection
    • 我认为这个解决方案在运行 JUnit 测试时不会起作用,因为context.getConnection() 返回MockSenderConnection。我正在使用MockWebServiceServer 进行单元测试。
    • 重要:必须启用设置自定义标头(spring 现在使用 Sun HttpConnection)! System.setProperty("sun.net.http.allowRestrictedHeaders", "true") 或者在VM启动时:-Dsun.net.http.allowRestrictedHeaders=true
    【解决方案3】:

    以下片段已使用 Spring 4.0 进行了测试。它将WebServiceMessageCallback 附加到org.springframework.ws.client.core.WebServiceTemplate

    final String DYNAMICVALUE = "myDynamo";
    
    WebServiceMessageCallback wsCallback = new WebServiceMessageCallback() {           
           public void doWithMessage(WebServiceMessage message) {
                try {
                            SoapMessage soapMessage = (SoapMessage)message;
                            SoapHeader header = soapMessage.getSoapHeader();
                            header.addAttribute(new QName("myHeaderElement"), DYNAMICVALUE);                        
                } catch (Exception e) {
                            e.printStackTrace();
                }
           }
    };
    
    JAXBElement<MyWsResponse> response = (JAXBElement<MyWsResponse>)
            wsTemplate.marshalSendAndReceive(MyWsOP, wsCallback);
    

    【讨论】:

    • 问题是“如何设置自定义 HTTP 标头(不是 SOAP 标头)”,但这个答案实际上添加了 SOAP 标头,而不是 HTTP 标头。
    【解决方案4】:

    Spring 的 webServiceTemplate.marshalSendAndReceive(request) 方法内部使用 HttpComponentsMessageSender 通过网络发送 SOAP 消息,这进一步使用 WebServiceConnection 与服务器建立 http 连接。您所要做的就是编写自己的自定义 HttpComponentsMessageSender 并在 postMethod 中设置 cookie。

    客户发件人代码:

        package com.swap.ws.sender;
    
    import java.io.IOException;
    import java.net.URI;
    
    import javax.annotation.Resource;
    
    import org.apache.http.client.methods.HttpPost;
    import org.apache.log4j.Logger;
    import org.springframework.stereotype.Service;
    import org.springframework.ws.transport.WebServiceConnect ion;
    import org.springframework.ws.transport.http.HttpComponen tsConnection;
    
    /**
    * 
    * @author swapnil Z
    */
    @Service("urlMessageSender")
    public class CustomHttpComponentsMessageSender extends
    org.springframework.ws.transport.http.HttpComponen tsMessageSender {
    private static Logger _logger = Logger.getLogger("");
    
    
    @Override
    public WebServiceConnection createConnection(URI uri) throws IOException {
    String cookie = null;
    HttpComponentsConnection conn = (HttpComponentsConnection) super
    .createConnection(uri);
    HttpPost postMethod = conn.getHttpPost();
    cookie = "<Your Custom Cookie>";
    
    postMethod.addHeader("Cookie", cookie);
    
    return conn;
    }
    }
    

    弹簧配置:

    <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMe ssageFactory" />
    
    <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshalle r">
    <property name="contextPath" value="com.swap.provision" />
    </bean>
    
    <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServi ceTemplate">
    <constructor-arg ref="messageFactory" />
    <property name="marshaller" ref="marshaller"></property>
    <property name="unmarshaller" ref="marshaller"></property>
    <property name="messageSender" ref="urlMessageSender"/>
    <property name="defaultUri" value=<Server URL> />
    </bean>
    

    在此之后,我只需获取 bean webServiceTemplate 并调用 marshalSendAndReceive 方法。因此,在进行 HTTP 调用之前,每个请求都会设置其自定义 cookie。

    【讨论】:

      【解决方案5】:

      当使用spring integration 3和spring integration-ws时,可以使用以下代码来处理请求:

      public boolean handleRequest(MessageContext messageContext)
              throws WebServiceClientException {
          TransportContext context = TransportContextHolder.getTransportContext();
          HttpUrlConnection connection = (HttpUrlConnection) context
          .getConnection();
          connection.getConnection().addRequestProperty("HEADERNAME",
          "HEADERVALUE");
      
          return true;
      }
      

      拦截器可以通过以下方式连接到出站网关:

      <ws:outbound-gateway ...            
              interceptor="addPasswordHeaderInterceptor" >
      </ws:outbound-gateway>
      
      <bean id="addPasswordHeaderInterceptor class="com.yourfirm.YourHttpInterceptor" />
      

      【讨论】:

        【解决方案6】:

        其实它是@Tomasz的答案的更新版本,但是提供了新的Spring-WS API、Java 8快捷方式,并且关心用单独的方法创建WebServiceMessageCallback实例。

        我相信它更明显和自给自足。

        final class Service extends WebServiceGatewaySupport {
        
            /**
             * @param URL       the URI to send the message to
             * @param payload   the object to marshal into the request message payload
             * @param headers   HTTP headers to add to the request
             */
            public Object performRequestWithHeaders(String URL, Object payload, Map<String, String> headers) {
                return getWebServiceTemplate()
                        .marshalSendAndReceive(URL, payload, getRequestCallback(headers));
            }
        
            /**
             * Returns a {@code WebServiceMessageCallback} instance with custom HTTP headers.
             */
            private WebServiceMessageCallback getRequestCallback(Map<String, String> headers) {
                return message -> {
                    TransportContext context = TransportContextHolder.getTransportContext();
                    HttpUrlConnection connection = (HttpUrlConnection)context.getConnection();
                    addHeadersToConnection(connection, headers);
                };
            }
        
            /**
             * Adds all headers from the {@code headers} to the {@code connection}.
             */
            private void addHeadersToConnection(HttpUrlConnection connection, Map<String, String> headers){
                headers.forEach((name, value) -> {
                    try {
                        connection.addRequestHeader(name, value);
                    } catch (IOException e) {
                        e.printStackTrace(); // or whatever you want
                    }
                });
            }
        
        }
        

        【讨论】:

        • 我将如何使用这个类?我已经有一个从 WSDL 生成的服务类。
        • @Pretty,使用此处指定的 URL 和有效负载,并在此处传递它们
        【解决方案7】:

        使用 java 1.8 的示例方法:如何添加 HTTP 标头:

        public void executeObjectWebservice(String id) {
                ExecuteObject request = new ExecuteObject();
                getWebServiceTemplate().marshalSendAndReceive("http://url/webservice-test/uc4ws",
                        new ObjectFactory().createExecuteObject(request), new WebServiceMessageCallback() {
                            public void doWithMessage(WebServiceMessage message) throws IOException {
                                TransportContext context = TransportContextHolder.getTransportContext();
                                HttpUrlConnection connection = (HttpUrlConnection) context.getConnection();
                                connection.addRequestHeader("ID", id);
                            }
                        });    
                }
        

        解释: 使用 getWebServiceTemplate().marshalSendAndReceive,例如此处所述:https://spring.io/guides/gs/consuming-web-service/

        第一个参数是URI,第二个参数是请求发送的对象。作为第三个参数,您可以添加为函数

        new WebServiceMessageCallback()
        

        覆盖public void doWithMessage 的位置。此方法在发送请求之前被调用。您可以在其中访问消息并通过

        添加请求标头
        TransportContext context = TransportContextHolder.getTransportContext();
        HttpUrlConnection connection = (HttpUrlConnection) context.getConnection();
        connection.addRequestHeader("ID", id);
        

        【讨论】:

        • 你没有得到什么?
        猜你喜欢
        • 1970-01-01
        • 2017-01-19
        • 1970-01-01
        • 2018-12-04
        • 2022-08-18
        • 2021-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多