Создав клиент веб-службы Java с помощью wsimport на wsdl, мне нужно установить заголовок авторизации для каждого сообщения SOAP, встроенного в HTTP-запрос. Создав подкласс javax.xml.ws.Service, как я могу добавить заголовок http к каждому исходящему запросу ???
клиент веб-службы java, добавляющий заголовки http
Ответы (5)
Вы можете передать карту с настраиваемыми заголовками в BindingProvider (я считаю, что вы можете установить свойство MessageContext.HTTP_REQUEST_HEADERS). Попробуйте создать заголовок авторизации и передать его.
Вот код, основанный на ответе Феми.
Это может быть немного сложно. Красиво работает!
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);
Map<String, String>
, потому что вы слишком быстро прочитали ответ. Не будь похожим на меня. Используйте Map<String, List<String>>
и сэкономьте четыре часа, которые я потратил на отладку HTTP transport error: java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List
.
- person L42; 15.11.2016
Dispatch<SOAPMessage> disp = jaxwsService.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);
Я не знаю, что такое portName
. Как мне создать новый экземпляр portName. Спасибо!
- person alan9uo; 23.09.2019
Для полноты картины и для того, чтобы помочь другим в подобных ситуациях, я хотел бы проиллюстрировать самое чистое решение IMHO с использованием цепочки обработчиков JAX-WS:
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(); }
}
В моем примере выше (и в моем продуктивном коде) я получаю данные для передачи в заголовки HTTP-запроса из ThreadLocale
, то есть из контекста моего текущего потока. Поскольку это WebserviceContext
мой собственный класс, вам нужно будет реализовать свой собственный способ доступа к своим данным.
Чтобы дополнить ответы Daniel Alexiuc и Femi, вот несколько альтернативный способ, основанный на этой документации: https://javaee.github.io/metro/doc/user-guide/user-guide.html#adding-soap-headers-when-send-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-запрос
когда вы отправляете сообщение в режиме сообщения, вы также можете передавать MimeHeaders в сообщении SOAP, которое в конечном итоге преобразуется в заголовки http, то есть:
soapMessage.getMimeHeaders().addHeader("Authorization","Basic [md5]")