使用Spring的WebServiceTemplate无法将Http标头添加到消息中

时间:2018-02-05 13:18:14

标签: java spring soap header webservicetemplate

我有一个相当简单的例子,我正在尝试将HTTP标头(而不是SOAP标头)添加到我使用Spring WebServiceTemplate创建的请求中。

我已经定义了ClientInterceptor我正在做的事情:

@Override
    public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {

        try {
            TransportContext context = TransportContextHolder.getTransportContext();
            HttpComponentsConnection connection = (HttpComponentsConnection) context.getConnection();
            connection.addRequestHeader("Authorization", String.format("Bearer %s", someAccessToken));
        } catch (IOException exception) {
            // Do nothing
        }

        return true;
        }

这是我配置扩展SomeClient的{​​{1}}的方式:

WebServiceConfigurationSupport

但是没有添加@Bean public SomeClient someClient() { ... SomeClientImpl service = new SomeClientImpl(); service.setObjectFactory(new com.path.ObjectFactory()); service.setDefaultUri(someUri); service.setMarshaller(marshaller); service.setUnmarshaller(marshaller); service.setxStreamMarshaller(xStreamMarshaller); service.setInterceptors(new ClientInterceptor[]{wss4jSecurityInterceptor()}); service.setMessageSender(new HttpComponentsMessageSender()); service.setInterceptors(new ClientInterceptor[]{wss4jSecurityInterceptor(), addHttpHeaderInterceptor()}); return service; } @Bean public ClientInterceptor addHttpHeaderInterceptor() { return new AddHttpHeaderInterceptor(someAccessToken); } @Bean public Wss4jSecurityInterceptor wss4jSecurityInterceptor() { Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor(); interceptor.setSecurementActions(securementAction); interceptor.setSecurementUsername(securementUsername); interceptor.setSecurementPassword(securementPassword); interceptor.setSecurementPasswordType(WSConstants.PW_TEXT); interceptor.setSecurementMustUnderstand(false); return interceptor; } 标头。我还尝试了Authorization

CustomMessageCallback

但似乎没有效果。我做错了什么,为什么没有添加public class CustomMessageCallback implements WebServiceMessageCallback { private String headerKey; private String headerValue; public CustomMessageCallback(String headerKey, String headerValue) { this.headerKey = headerKey; this.headerValue = headerValue; } @Override public void doWithMessage(WebServiceMessage webServiceMessage) throws IOException, TransformerException { TransportContext context = TransportContextHolder.getTransportContext(); HttpComponentsConnection conn = (HttpComponentsConnection) context.getConnection(); HttpPost post = conn.getHttpPost(); post.addHeader(headerKey, headerValue); } } 标题?谢谢!

3 个答案:

答案 0 :(得分:1)

使用HeadersAwareSenderWebServiceConnection接口而不是实际的基础连接。

TransportContext context = TransportContextHolder.getTransportContext();
HeadersAwareSenderWebServiceConnection connection = (HeadersAwareSenderWebServiceConnection) context.getConnection();
connection.addRequestHeader("Authorization", String.format("Bearer %s", "********"));

现在,如果您升级/切换HTTP库,则无需更改此代码。

回答你关于你做错了什么的问题是你正在向错误的班级投掷。是的,您正在使用的类已弃用但它是您正在使用的库的一部分,您不能仅在不更改底层HTTP库的情况下转换为其他类。

答案 1 :(得分:0)

我过去做的是使用像这样的WebServiceMessageCallback

public class WsHttpHeaderCallback implements WebServiceMessageCallback
{
    private String headerKey;
    private String headerValue;
    private String soapAction;

    public WsHttpHeaderCallback(String headerKey, String headerValue, String soapAction)
    {
        super();
        this.headerKey = headerKey;
        this.headerValue = headerValue;
        this.soapAction = soapAction;
        validateRequiredFields();
    }

    public WsHttpHeaderCallback()
    {
        super();
    }

    @Override
    public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException
    {
        validateRequiredFields();
        addRequestHeader(headerKey, headerValue);
        if (StringUtils.hasText(this.soapAction))
        {
            AxiomSoapMessage axiomMessage = (AxiomSoapMessage) message;
            axiomMessage.setSoapAction(this.soapAction);
        }       
    }
    private void validateRequiredFields()
    {
        if( !StringUtils.hasText(headerKey) )
        {
            throw new IllegalArgumentException("Impossibile proseguire. Passato HEADER HTTP con chiave non valida: ["+headerKey+"]");
        }
        if( !StringUtils.hasText(headerValue) )
        {
            throw new IllegalArgumentException("Impossibile proseguire. Passato HEADER HTTP con valore non valido: ["+headerValue+"]");
        }       
    }
    private void addRequestHeader(String headerKey, String headerValue)
    {
        TransportContext context = TransportContextHolder.getTransportContext();
        WebServiceConnection connection = context.getConnection();
        if (connection instanceof HttpComponentsConnection)
        {
            HttpComponentsConnection conn = (HttpComponentsConnection) connection;
            HttpPost post = conn.getHttpPost();
            post.addHeader(headerKey, headerValue); 
        }
        else if( connection instanceof ClientHttpRequestConnection )
        {
            ClientHttpRequestConnection conn = (ClientHttpRequestConnection)connection;
            conn.getClientHttpRequest().getHeaders().add(headerKey, headerValue);
        }
    }   
}

然后我以这种方式使用它:

wsTemplate.marshalSendAndReceive(wsUrl, request, new WsHttpHeaderCallback(headerKey, headerValue, soapAction) );

通过这种方式,我成功设置了所有需要的HttpHeaders(在我的例子中只有一个:))

我希望它有用

安吉洛

答案 2 :(得分:0)

TL; DR 您的 messageSender 应该是 HttpComponentsMessageSender 的实例,而不是 HttpUrlConnectionMessageSender 。您还需要提供适当的凭据。

getConnection() TransportContext 的功能会返回 WebServiceConnection 的实施。 HttpUrlConnection HttpComponentsConnection 都是相同的实现。所以基本上你得到了错误的连接类型,因此 ClassCastException

ClientInterceptor 适用于自定义标头,但不适用于授权标头。为此,您的 HttpComponentsMessageSender 需要使用您的凭据进行配置。

正确的配置应该像this

@Value("${username}")
private String username;

@Value("${password}")
private String password;

@Bean
public SomeClient someClient() {

  SomeClientImpl service =  new SomeClientImpl();
  service.setMessageSender();
  //other configs

  return service;
}

public HttpComponentsMessageSender getMessageSender(){
  HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
  httpComponentsMessageSender.setCredentials(getCredentials);
}

public UsernamePasswordCredentials getCredentials(){
  return new UsernamePasswordCredentials(username, password);
}