开发者

java web service client, adding http headers

Having created a java web service client using wsimport on a wsdl, I need to set the Authorization header for each soap message embedded in an http request. Having generated a subclass of javax.xml.ws.Service, how can I append an http heade开发者_运维知识库r to each outgoing request???


Here is the code, based on Femi's answer.

It can be a little tricky to figure out. Works beautifully!

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);


You can pass a map with custom headers to the BindingProvider (I believe you can set the MessageContext.HTTP_REQUEST_HEADERS property). Try creating an Authorization header and passing it in.


To supplement answers of Daniel Alexiuc and Femi here is slightly alternative way based on this documentation: 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;
    }
}

This will add header to http request


For the sake of completeness and to help others in similar situations, I'd like to illustrate the IMHO cleanest solution using the JAX-WS-handler-chain:

1) Sub-class your service-class (not the port-class) in a different (non-generated) package. Because the service-class (and its entire package) was likely generated from a WSDL, your changes to the sub-class are not lost, when you update your service-class after a WSDL change.

2) Annotate your service-sub-class like this (import javax.jws.HandlerChain):

@HandlerChain(file="HandlerChain.xml")
public class MyService extends GeneratedService {

3) Create a file called HandlerChain.xml in the same package as your service-sub-class, i.e. next to MyService with the following content:

<?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>

You may add multiple <handler> elements, btw.

And make sure that this file really ends up in your JAR! For example, when using Maven, you have to place it either in ${project}/src/main/resources/ (instead of ${project}/src/main/java/) or you have to change your build-configuration to include resources from the java-folder! I recommend the latter, because it's cumbersome to have a parallel package-structure in the resources-folder, which is often forgotten during refactorings.

4) Implement your HttpHeaderExtensionSOAPHandler -- similar to this:

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(); }
}

In my example above (and in my productive code) I obtain the data to be passed into the HTTP request headers from a ThreadLocale, i.e. my current thread's context. Since this WebserviceContext is my custom class, you'll need to implement your own way to access your data.


when you're sending in Message mode, you can also pass MimeHeaders on SOAP Message, which will eventually translate into http headers, i.e:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜