2

我有一个相当简单的案例,我试图将 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;
        }

这就是我配置SomeClientwhich extends的方式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);
    }
}

但它似乎也不起作用。我在做什么错,为什么Authorization没有添加标题?谢谢!

4

3 回答 3

5

使用HeadersAwareSenderWebServiceConnection接口而不是实际的底层连接。

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

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

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

于 2018-02-05T13:54:05.257 回答
1

我过去所做的是使用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(在我的情况下只有一个:))

我希望它有用

安杰洛

于 2018-02-05T14:01:49.763 回答
0

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

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

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

正确的配置应该是这样的

@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);
}
于 2018-02-05T14:10:12.567 回答