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

使用wsimport导入的Web Service调用时SOAP Header参数设置求助

解决SOAP Header认证失败的问题

我一眼就看出问题所在了:你当前代码里设置的是HTTP请求头,但你的Web服务要求的是SOAP消息自身的Header区域(也就是你给出的WSDL里<soap:Header>标签下的authUser结构),这两者完全不是同一个东西,所以你的认证参数根本没传到服务期望的位置,自然会返回Authentication Error。

下面给你两种靠谱的解决方案,都是针对SOAP Header的正确设置方式:

方法一:使用wsimport生成的Header类(最规范)

当你用wsimport生成客户端代码时,它应该已经根据WSDL里的authUser结构生成了对应的Java类(比如AuthUser,具体类名可能根据WSDL的命名规则略有调整)。你可以直接通过WSBindingProvider的setRequestHeader方法设置这个对象:

public static void main(String[] args) {
    System.out.println("Hello world");
    WsTest wsTest = new WsTest();
    WsTestSoap client = wsTest.getWsTestSoap();

    // 转换为WSBindingProvider以便操作SOAP Header
    WSBindingProvider bindingProvider = (WSBindingProvider) client;

    // 创建WSDL定义的authUser对象,填充用户名密码
    AuthUser authUser = new AuthUser();
    authUser.setUserName("xxxxx");
    authUser.setPassword("xxxxx");
    // 如果服务需要authenticationToken,取消下面注释并赋值
    // authUser.setAuthenticationToken("your-token-here");

    // 设置SOAP Header,注意命名空间要和WSDL里的完全一致:http://tempuri.org/
    bindingProvider.setRequestHeader(
        "http://tempuri.org/",
        "authUser",
        authUser
    );

    try {
        String re1 = client.authenticateUser();
        String re2 = client.existencias("xxxx");
        System.out.println(re1);
        System.out.println(re2);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

方法二:自定义SOAP Handler(手动构建Header)

如果wsimport没有生成对应的AuthUser类,或者你需要更灵活地控制SOAP消息结构,可以自定义一个SOAPHandler来手动构建Header:

第一步:编写Handler类

import javax.xml.namespace.QName;
import javax.xml.soap.*;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.util.Set;

public class AuthHeaderHandler implements SOAPHandler<SOAPMessageContext> {
    private final String userName;
    private final String password;

    public AuthHeaderHandler(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    @Override
    public Set<QName> getHeaders() {
        // 返回我们要处理的Header的QName,对应WSDL里的authUser
        QName authUserQName = new QName("http://tempuri.org/", "authUser");
        return Set.of(authUserQName);
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        // 只处理 outbound(发送出去的)消息
        Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (isOutbound) {
            try {
                SOAPMessage soapMsg = context.getMessage();
                SOAPEnvelope envelope = soapMsg.getSOAPPart().getEnvelope();
                SOAPHeader header = envelope.getHeader();

                // 如果Header不存在,创建一个
                if (header == null) {
                    header = envelope.addHeader();
                }

                // 构建authUser元素,注意命名空间和前缀要和WSDL一致
                QName authUserQName = new QName("http://tempuri.org/", "authUser", "tem");
                SOAPElement authUserElement = header.addChildElement(authUserQName);

                // 添加userName子元素
                SOAPElement userNameElem = authUserElement.addChildElement("userName", "tem");
                userNameElem.setTextContent(userName);

                // 添加password子元素
                SOAPElement passwordElem = authUserElement.addChildElement("password", "tem");
                passwordElem.setTextContent(password);

                // 可选:如果需要authenticationToken,取消下面注释
                // SOAPElement tokenElem = authUserElement.addChildElement("authenticationToken", "tem");
                // tokenElem.setTextContent("your-token");

                soapMsg.saveChanges();
            } catch (SOAPException e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

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

    @Override
    public void close(MessageContext context) {
        // 无需额外清理,留空即可
    }
}

第二步:在客户端代码中添加Handler

import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;

public static void main(String[] args) {
    System.out.println("Hello world");
    WsTest wsTest = new WsTest();
    WsTestSoap client = wsTest.getWsTestSoap();

    WSBindingProvider bindingProvider = (WSBindingProvider) client;

    // 创建Handler实例并添加到客户端的Handler链中
    List<Handler> handlerChain = new ArrayList<>();
    handlerChain.add(new AuthHeaderHandler("xxxxx", "xxxxx"));
    bindingProvider.getBinding().setHandlerChain(handlerChain);

    try {
        String re1 = client.authenticateUser();
        String re2 = client.existencias("xxxx");
        System.out.println(re1);
        System.out.println(re2);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

为什么原来的代码会失败?

你之前用request.put(MessageContext.HTTP_REQUEST_HEADERS, headers)设置的是HTTP协议级别的请求头(比如我们常见的Authorization、Content-Type这类),但你的服务要求的是SOAP消息体内部的soap:Header标签里的结构化数据,这是SOAP协议自身的Header,和HTTP头完全是两个层面的东西,所以服务根本没收到你的认证参数,自然返回认证错误。

内容的提问来源于stack exchange,提问作者Isaac Mena

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:57:37