用于Microsoft WCF服务的Apache CXF客户端,MTOM返回400

clo*_*ker 14 java wcf web-services cxf

我有一个用于Microsoft WCF服务的apache CXF客户端,我试图通过MTOM发送文件.但是,我一直得到400,根据合作伙伴的WCF方面的错误是创建MTOM阅读器时出错

我已经跟踪了出站消息,它看起来像这样:

INFO: Outbound Message
---------------------------
ID: 1
Address: https://someserver.com/ImportService.svc?wsdl
Encoding: UTF-8
Http-Method: POST
Content-Type: multipart/related; type="application/xop+xml"; boundary="uuid:1d46d7c9-047b-440d-928b-ab8689ab5e6f"; start="<root.message@cxf.apache.org>"; start-info="application/soap+xml; action=\"http://tempuri.org/IImportService/UploadFile\""
Headers: {Accept=[*/*], Accept-Encoding=[gzip;q=1.0, identity; q=0.5, *;q=0], Content-Encoding=[gzip]}
Payload: --uuid:1d46d7c9-047b-440d-928b-ab8689ab5e6f
Content-Type: application/xop+xml; charset=UTF-8; type="application/soap+xml; action=\"http://tempuri.org/IImportService/UploadFile\""
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

    <?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="true">
            <wsse:UsernameToken wsu:Id="UsernameToken-e51a6fdd-5053-4aae-a9fb-363dde7d9e77">
                <wsse:Username>blah@test.com</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mypassword</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
        <ns2:letterOptions xmlns="http://schemas.datacontract.org/2004/07/PublicServices.Import" xmlns:ns2="http://tempuri.org/">
            <EnableQBPlanConsolidation>false</EnableQBPlanConsolidation>
            <MASKSSN>true</MASKSSN>
            <SRPrintedNumberofDays>2</SRPrintedNumberofDays>
            <SuppressAllLetters>false</SuppressAllLetters>
            <SuppressNewMemberLoginLetter>false</SuppressNewMemberLoginLetter>
            <SuppressTakeOverLetterForTermed>false</SuppressTakeOverLetterForTermed>
            <SuppressTerminationLetter>false</SuppressTerminationLetter>
        </ns2:letterOptions>
        <ns2:JobQueueType xmlns="http://schemas.datacontract.org/2004/07/PublicServices.Import" xmlns:ns2="http://tempuri.org/">Import</ns2:JobQueueType>
        <Filename xmlns="http://tempuri.org/">testImport.csv</Filename>
        <Action xmlns="http://www.w3.org/2005/08/addressing">http://tempuri.org/IImportService/UploadFile</Action>
        <MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:f380e4cc-225f-4b7d-bd46-6b5d607a59ca</MessageID>
        <To xmlns="http://www.w3.org/2005/08/addressing">https://someserver.com/ImportService.svc?wsdl</To>
        <ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
            <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
        </ReplyTo>
    </soap:Header>
    <soap:Body>
        <FileUploadMessage xmlns="http://tempuri.org/" xmlns:ns2="http://schemas.datacontract.org/2004/07/PublicServices.Import" xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/">
            <FileByteStream>
                <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:68e0408d-81da-496b-a06c-24a0459207d1-1@tempuri.org"/>
            </FileByteStream>
        </FileUploadMessage>
    </soap:Body>
</soap:Envelope>
--uuid:1d46d7c9-047b-440d-928b-ab8689ab5e6f
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <68e0408d-81da-496b-a06c-24a0459207d1-1@tempuri.org>

[VERSION],1.0
[NPM],552652222,1,Basic Client,Basic Client,Bob,Z,Jones,MR,bjones@test.com,402444555,,1234 Some street,,Omaha,NE,68123,,M,T,F,F

--uuid:1d46d7c9-047b-440d-928b-ab8689ab5e6f--
Run Code Online (Sandbox Code Playgroud)

我发现很多其他人都遇到同样的问题:https: //coderanch.com/t/224995/java/Apache-CXF-MTOM-enabled-WCF

请求WCF服务合同时出现HTTP错误请求错误

http://mail-archives.apache.org/mod_mbox/cxf-users/201211.mbox/%3CCAPXLCrCLkSkC8dQFeuU8DLY6gne1SOhwT9eMDxAUxLudnqU+YA@mail.gmail.com%3E

这些都无法解决我的问题.我尝试了多个不同版本的CXF,我得到了同样的错误.

这是调用服务的代码的合并版本:

    JaxWsProxyFactoryBean proxyFactory = new JaxWsProxyFactoryBean();
    proxyFactory.setBindingId(SOAPBinding.SOAP12HTTP_MTOM_BINDING);
    proxyFactory.setServiceClass(IImportService.class);
    proxyFactory.setAddress(proxyEndpoint);
    proxyFactory.getFeatures().add(new WSAddressingFeature());

    IImportService importService = (IImportService) proxyFactory.create();

    Client client = (Client) importService;

    LetterOptions letterOptions = new LetterOptions();
    letterOptions.setSRPrintedNumberofDays(2);
    letterOptions.setMASKSSN(true);
    letterOptions.setEnableQBPlanConsolidation(false);

    List<Object> headerList = new ArrayList<>();

    headerList.add(new Header(new QName("http://tempuri.org/", "letterOptions"),
            letterOptions, new JAXBDataBinding(LetterOptions.class)));
    headerList.add(new Header(new QName("http://tempuri.org/", "JobQueueType"), JobQueueType.IMPORT, new JAXBDataBinding(JobQueueType.class)));
    headerList.add(new Header(new QName("http://tempuri.org/", "Filename"), "testImport.csv", new JAXBDataBinding(String.class)));

    client.getRequestContext().put(Header.HEADER_LIST, headerList);
    client.getEndpoint().getActiveFeatures().add(new LoggingFeature());

    client.getInInterceptors().add(new GZIPInInterceptor());
    client.getInInterceptors().add(new LogResponseInterceptor());

    GZIPOutInterceptor outInterceptor = new GZIPOutInterceptor();
    outInterceptor.setForce(true);
    client.getOutInterceptors().add(outInterceptor);

    Map props = new HashMap();
    props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
    props.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    props.put(WSHandlerConstants.PW_CALLBACK_CLASS, PasswordCallbackHandler.class.getName());
    props.put(WSHandlerConstants.USER, "blah@test.com");
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(props);
    client.getOutInterceptors().add(wssOut);

    HTTPConduit conduit = (HTTPConduit) client.getConduit();
    HTTPClientPolicy policy = conduit.getClient();
    if(policy == null) {
        policy = new HTTPClientPolicy();
    }
    policy.setAllowChunking(false);

    FileUploadMessageReponse response = importService.uploadFile(fileUploadMessage);
Run Code Online (Sandbox Code Playgroud)

一个有趣的小问题是,我可以复制正在登录到SoapUI的相同请求,并且它可以正常工作.

Mar*_*coz -1

当尝试使用 Apache CXF 通过 MTOM 将文件发送到 Microsoft WCF 服务时,您似乎遇到了 400 Bad Request 错误。此问题可能是由于多种因素造成的,例如消息格式不正确、配置不兼容或服务器端限制。

错误的潜在原因之一可能与 SOAP 消息格式或 MTOM 处理有关。以下是代码的更新版本,其中包含一些修改和其他配置,可能有助于解决问题:

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.message.Message;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.ws.addressing.WSAddressingFeature;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.util.Base64;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Holder;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MTOMFileUploadClient {

    public static void main(String[] args) {
        // Set the URL of the WCF service
        String serviceURL = "https://someserver.com/ImportService.svc";

        // Create a JAX-WS proxy factory bean
        JaxWsProxyFactoryBean proxyFactory = new JaxWsProxyFactoryBean();
        proxyFactory.setServiceClass(IImportService.class);
        proxyFactory.setAddress(serviceURL);
        proxyFactory.getFeatures().add(new WSAddressingFeature());

        // Create the MTOM enabled client proxy
        IImportService importService = (IImportService) proxyFactory.create();

        // Configure the client for MTOM
        Client client = ClientProxy.getClient(importService);
        client.getInInterceptors().add(new LoggingInInterceptor());
        client.getOutInterceptors().add(new LoggingOutInterceptor());
        client.getOutInterceptors().add(new WSS4JOutInterceptor(getSecurityProperties()));

        // Configure HTTP conduit for the client
        HTTPConduit conduit = (HTTPConduit) client.getConduit();
        HTTPClientPolicy policy = conduit.getClient();
        if (policy == null) {
            policy = new HTTPClientPolicy();
        }
        policy.setAllowChunking(false);
        conduit.setClient(policy);

        // Upload file via MTOM
        File file = new File("testImport.csv");
        FileUploadMessage fileUploadMessage = new FileUploadMessage();
        fileUploadMessage.setFileByteStream(new DataHandler(new FileInputStream(file), "application/octet-stream"));
        fileUploadMessage.setFilename(file.getName());
        FileUploadMessageReponse response = importService.uploadFile(fileUploadMessage);
    }

    private static Map<String, Object> getSecurityProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        props.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
        props.put(WSHandlerConstants.USER, "blah@test.com");
        props.put(WSHandlerConstants.PW_CALLBACK_CLASS, PasswordCallbackHandler.class.getName());
        props.put(SecurityConstants.ENCRYPT_PROPERTIES, "clientKeystore.properties");
        props.put(SecurityConstants.ENCRYPT_USERNAME, "client");
        props.put(SecurityConstants.ENCRYPT_PASSWORD, "clientpassword");
        props.put(SecurityConstants.ENCRYPTION_USER, "servercert");

        return props;
    }
}
Run Code Online (Sandbox Code Playgroud)

在此代码中:

  • BindingID我们通过将设为 来将客户端配置为使用 MTOM SOAPBinding.SOAP12HTTP_MTOM_BINDING
  • 我们添加日志拦截器来记录客户端和服务器之间交换的 SOAP 消息,以用于调试目的。
  • 我们使用 配置 UsernameToken 身份验证所需的安全属性WSS4JOutInterceptor
  • 我们在 HTTP 管道中禁用分块,因为某些服务器可能不支持分块传输编码。
  • 我们FileUploadMessage用文件字节流和文件名构造对象。

确保将serviceURLfile、 和 等占位符替换security properties为特定于您的环境的实际值。

此外,请确保 WCF 服务已正确配置为接受 MTOM 消息,并且任何服务器端约束(例如消息大小限制)均得到相应调整。