Java Web服务客户端,添加HTTP头部

23

我使用wsimport在一个WSDL上创建了一个Java Web服务客户端,现在需要为每个嵌入在HTTP请求中的SOAP消息设置Authorization标头。 由于已经生成了javax.xml.ws.Service的子类,因此该如何将HTTP标头附加到每个出站请求中?


这篇博客文章展示了如何修改HttpRequestHeaders。它假设你正在编写一个J2EE应用程序。 - David Weiser
5个回答

25

这是基于Femi的答案的代码。

可能有点棘手,但运行得非常好!

Service jaxwsService = Service.create(wsdlURL, serviceName);
Dispatch<SOAPMessage> disp = jaxwsService.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);

//Add HTTP request Headers
Map<String, List<String>> requestHeaders = new HashMap<>();
requestHeaders.put("Auth-User", Arrays.asList("BILL_GATES"));
disp.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);

我在createDispatch调用中遇到了一些问题: Dispatch<SOAPMessage> disp = jaxwsService.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);它抱怨找不到合适的方法。我有什么明显的遗漏吗? 我正在导入 import javax.xml.soap.SOAPMessage; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; import javax.xml.ws.handler.MessageContext; - Mark McWhirter
7
谢谢!如果你和我一样傻,可能会尝试使用 Map<String, String>,因为你读答案太快了。不要像我这样,使用 Map<String, List<String>>,并节省我花费四个小时来调试 HTTP transport error: java.lang.ClassCastException:java.lang.String cannot be cast to java.util.List - L42
非常好的回答!但我有一个问题。在这一行中:Dispatch<SOAPMessage> disp = jaxwsService.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE); 我不知道 portName 是什么。我该如何创建 portName 实例。谢谢! - alan9uo

14
您可以将带有自定义标头的映射传递给BindingProvider(我相信您可以设置MessageContext.HTTP_REQUEST_HEADERS属性)。 尝试创建一个授权标头并将其传递进去。

10

为了补充Daniel Alexiuc和Femi的回答,这里提供一种基于此文档的略微不同的方式:https://javaee.github.io/metro/doc/user-guide/user-guide.html#adding-soap-headers-when-sending-requests

public class HelloClient {

   @WebServiceRef(wsdlLocation="http://localhost:8080/helloservice/hello?wsdl")
   static HelloService service;


   public HelloPort getHelloPort(){
       HelloPort helloPort = service.getHelloPort();

       Map<String, List<String>> requestHeaders = new HashMap<>();
       requestHeaders.put("Your_Header",Arrays.asList("Your_Header_value"));

       BindingProvider bindingProvider = (BindingProvider)helloPort;
       bindingProvider.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);

       return helloPort;
    }
}

这将向 HTTP 请求添加头信息


8
为了完整性并帮助其他类似情况的人,我想用 JAX-WS-handler-chain 演示在我看来最干净的解决方案:
1) 在一个不同的(非生成的)包中对您的服务类(而不是端口类)进行子类化。由于服务类(及其整个包)很可能是从 WSDL 生成的,所以在更新 WSDL 后,对子类进行的更改不会丢失。
2) 如下所示注释您的服务子类(导入javax.jws.HandlerChain):
@HandlerChain(file="HandlerChain.xml")
public class MyService extends GeneratedService {

3) 在与您的服务子类相同的包中创建一个名为HandlerChain.xml的文件,即在MyService旁边,其内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
    <handler-chain>
        <handler>
            <handler-name>co.codewizards.example.HttpHeaderExtensionSOAPHandler</handler-name>
            <handler-class>co.codewizards.example.HttpHeaderExtensionSOAPHandler</handler-class>
        </handler>
    </handler-chain>
</handler-chains>

顺便说一下,您可以添加多个<handler>元素。

请确保这个文件真的出现在您的JAR包中!例如,当使用Maven时,您必须将其放置在${project}/src/main/resources/(而不是${project}/src/main/java/),或者您必须更改构建配置以包括来自java文件夹的资源!我推荐后者,因为在resources文件夹中有一个并行的包结构,容易在重构过程中被遗忘。

4)实现您的HttpHeaderExtensionSOAPHandler - 类似于以下内容:

import static com.google.common.base.Preconditions.*;

import java.util.*;

import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import co.codewizards.webservice.WebserviceContext;

public class HttpHeaderExtensionSOAPHandler implements SOAPHandler<SOAPMessageContext> {

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        checkNotNull(context, "context");

        Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        checkNotNull(outboundProperty, "outboundProperty");

        if (outboundProperty.booleanValue()) {
            WebserviceContext<?, ?> webserviceContext = WebserviceContext.getThreadWebserviceContextOrFail();
            String something = (String) webserviceContext.___(); // my API method ;-)

            @SuppressWarnings("unchecked")
            Map<String, List<String>> requestHeaders = (Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
            if (requestHeaders == null) {
                requestHeaders = new HashMap<String, List<String>>();
                context.put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
            }
            requestHeaders.put(MyService.MY_CONSTANT, Collections.singletonList(something));
        }
        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) { return true; }

    @Override
    public void close(MessageContext context) { }

    @Override
    public Set<QName> getHeaders() { return Collections.emptySet(); }
}

在我上面的示例(以及我的生产代码)中,我从ThreadLocale获取要传递到HTTP请求标头中的数据,即当前线程的上下文。由于这个WebserviceContext是我的自定义类,您需要实现自己的方法来访问您的数据。


2

当您使用消息模式发送时,还可以在SOAP消息上传递MimeHeaders,这最终会转换为HTTP标头,例如:

soapMessage.getMimeHeaders().addHeader("Authorization","Basic [md5]")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接