You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DHL-SOAP API:如何为CreateShipmentOrderRequest添加SOAP认证头

问题原因

你当前代码添加的是HTTP协议层的Basic认证头,和接口要求的SOAP信封内的XML格式认证头完全是两个维度的内容,服务端解析请求时读不到要求的Authentification节点,就会一直返回登录失败。
你之前写的HTTP头添加逻辑可以直接删除,该接口不识别HTTP层的Basic认证。

解决方案

推荐两种实现方式,优先选第一种,代码改动量最小;如果因为项目使用的JAX-WS实现(CXF/Metro/Axis2)差异导致第一种不生效,用第二种Handler方案,通用性最强。

方式一:直接构造SOAP头注入请求上下文

不需要额外新增类,直接在原有初始化port的逻辑后追加SOAP头构造代码即可:

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPFactory;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.soap.SOAPBinding;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

// 原有初始化代码保留
GVAPI20De service = new GVAPI20De();
GKV3XAPIServicePortType port = service.getGKVAPISOAP11Port0();

Map<String, Object> req_ctx = ((BindingProvider)port).getRequestContext();
req_ctx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, CvpConstants.DHL_WSDL);
req_ctx.put("javax.xml.ws.client.connectionTimeout", "60000");

// --------------- 新增以下认证头构造逻辑 ---------------
// DHL接口cis前缀对应的固定命名空间,不要写错
final String CIS_NAMESPACE = "http://dhl.de/webservice/cisbase";
try {
    SOAPElement authNode = SOAPFactory.newInstance()
            .createElement(new QName(CIS_NAMESPACE, "Authentification", "cis"));
    // 拼接用户名节点
    SOAPElement userNode = authNode.addChildElement(new QName(CIS_NAMESPACE, "user", "cis"));
    userNode.setTextContent(CvpConstants.DHL_USER);
    // 拼接签名(密码)节点
    SOAPElement signatureNode = authNode.addChildElement(new QName(CIS_NAMESPACE, "signature", "cis"));
    signatureNode.setTextContent(CvpConstants.DHL_PASSWORD);

    // 把构造好的头注入请求上下文
    List<SOAPElement> headers = new ArrayList<>();
    headers.add(authNode);
    // 如果是Sun JDK自带的Metro实现用下面的key
    req_ctx.put("com.sun.xml.ws.api.message.Headers", headers.toArray(new SOAPElement[0]));
    // 如果是Apache CXF实现,注释掉上面一行,改用下面的key
    // req_ctx.put("javax.xml.ws.soap.headers", headers);
} catch (Exception e) {
    throw new RuntimeException("构造DHL SOAP认证头失败", e);
}
// --------------- 新增逻辑结束 ---------------

// 原有调用逻辑不变
CreateShipmentOrderResponse createShipmentOrder = port.createShipmentOrder(request);

方式二:自定义SOAPHandler注入认证头(通用方案)

这种方式不挑JAX-WS的具体实现,所有场景都能生效。
首先新增一个Handler类:

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;

public class DhlAuthSoapHandler implements SOAPHandler<SOAPMessageContext> {
    private static final String CIS_NAMESPACE = "http://dhl.de/webservice/cisbase";
    private final String dhlUser;
    private final String dhlPassword;

    public DhlAuthSoapHandler(String dhlUser, String dhlPassword) {
        this.dhlUser = dhlUser;
        this.dhlPassword = dhlPassword;
    }

    @Override
    public Set<QName> getHeaders() {
        return Collections.singleton(new QName(CIS_NAMESPACE, "Authentification", "cis"));
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        // 只处理发往服务端的出站请求
        Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!isOutbound) {
            return true;
        }
        try {
            SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
            SOAPHeader header = envelope.getHeader() == null ? envelope.addHeader() : envelope.getHeader();
            // 避免重复添加认证头
            Iterator<?> authNodes = header.getChildElements(new QName(CIS_NAMESPACE, "Authentification"));
            if (authNodes.hasNext()) {
                return true;
            }
            // 构造认证节点
            SOAPElement authNode = header.addChildElement("Authentification", "cis", CIS_NAMESPACE);
            SOAPElement userNode = authNode.addChildElement("user", "cis", CIS_NAMESPACE);
            userNode.setTextContent(dhlUser);
            SOAPElement sigNode = authNode.addChildElement("signature", "cis", CIS_NAMESPACE);
            sigNode.setTextContent(dhlPassword);
        } catch (Exception e) {
            throw new RuntimeException("添加DHL认证头失败", e);
        }
        return true;
    }

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

    @Override
    public void close(MessageContext context) {}
}

然后在你原有初始化port的代码后,绑定这个Handler即可:

// 初始化port完成后追加
BindingProvider bindingProvider = (BindingProvider) port;
List<javax.xml.ws.handler.Handler> handlerChain = new ArrayList<>();
handlerChain.add(new DhlAuthSoapHandler(CvpConstants.DHL_USER, CvpConstants.DHL_PASSWORD));
bindingProvider.getBinding().setHandlerChain(handlerChain);
注意事项
  • 确认cis前缀对应的命名空间和你本地生成的客户端代码里的命名空间一致,通常DHL接口的该命名空间固定为http://dhl.de/webservice/cisbase,如果命名空间写错,服务端无法识别认证头,依然会返回登录失败
  • 确认传入的用户名格式符合要求,一般为开发者ID_01这类格式,签名(密码)和用户名是对应关系,不要传错

内容的提问来源于stack exchange,提问作者Till Glöckner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 15:45:33