0

我有我试图通过SOAP访问,以创建新项目的SDL WorldServer的实例。如何通过SOAP API燃气附件发送DIME消息?

我想使通过谷歌Apps脚本在web应用程序,用户可以上传文件到,我可以用它来发送和使项目/报价斑点。我能够使SOAP适用于任何不需要附件的命令。但添加附件会使事情复杂化。我试过通过手动生成发送相同的SOAP消息,但是,当我尝试通过手动生成发送相同的SOAP消息时,我已经成功地通过soapui(但是,soapui为我处理DIME格式,因此我假设我需要使用DIME?消息我自己,我得到一个SOAP错误,指出:

<faultcode>soapenv:Server.userException</faultcode> 
<faultstring>java.io.IOException: Stream closed.</faultstring> 
<detail><ns1:hostname xmlns:ns1="http://xml.apache.org/axis/">SNJWS112</ns1:hostname></detail> 

这里是我使用的示例代码:

function makeDimeHeader (position, isChunk, id, contentType, data) { 
    // ref: http://xml.coverpages.org/draft-nielsen-dime-02.txt 
    var bin = "" 

    // version 1 
    bin += "00001" 

    if (position == "start") { 
    bin += "10" 
    } else if (position == "finish") { 
    bin += "01" 
    } else if (position == "middle") { 
    bin += "00" 
    } else if (position == "only") { 
    bin += "11" 
    } else { 
    throw "Error: position must be 'start', 'only', 'middle', or 'finish'" 
    } 

    if (isChunk) { 
    bin += "1" 
    } else { 
    bin += "0" 
    } 

    if (id.constructor !== Array) throw "Error: id must be a byte array" 
    if (contentType.constructor !== Array) throw "Error: contentType must be a byte array" 
    if (data.constructor !== Array) throw "Error: data must be a byte array" 

    var textType = Utilities.newBlob(contentType).getDataAsString() 

    if (textType.slice(0,4) == "http") { 
    bin += "0010" 
    } else if (contentType.length == 0) { 
    bin += "0000" 
    } else { 
    bin += "0001" 
    } 

    // RESERVED 
    bin += "0000" 

    // OPTIONS LENGTH 
    bin += "0000000000000000" 

    bin += ("0000000000000000" + id.length.toString(2)).slice(-16) 

    bin += ("0000000000000000" + contentType.length.toString(2)).slice(-16) 

    bin += ("00000000000000000000000000000000" + data.length.toString(2)).slice(-32) 

    var bytes = [] 
    for (var i = 0; i < bin.length/8; i++) { 
    num = parseInt(bin.slice(i*8,(i*8)+8),2); 
    // Byte[] is an Int8Array, not Uint8Array 
    if (num > 127) num = num - 256 
    bytes.push(num) 
    } 

    // PADDING TO CLOSEST 4 BYTES 
    if (id.length % 4 != 0) bytes = bytes.concat([0, 0, 0].slice(0, 4 - (id.length % 4))) 
    bytes = bytes.concat(id) 

    // PADDING TO CLOSEST 4 BYTES 
    if (contentType.length % 4 != 0) bytes = bytes.concat([0, 0, 0].slice(0, 4 - (contentType.length % 4))) 
    bytes = bytes.concat(contentType) 

    // PADDING TO CLOSEST 4 BYTES 
    if (data.length % 4 != 0) bytes = bytes.concat([0, 0, 0].slice(0, 4 - (data.length % 4))) 
    bytes = bytes.concat(data) 

    return bytes 

} 

function testPost() { 
    var file = UrlFetchApp.fetch("https://.../somedoc.xlsx"); 
    var fileBlob = file.getBlob(); 
    var fileBytes = fileBlob.getBytes(); 

    var contentType = 'application/dime; charset=Utf-8'; 

    var data = Utilities.newBlob(
    "<?xml version=\"1.0\"?>\r\n" + 
    "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:com=\"http://www.idiominc.org/com.idiominc.webservices.WorkflowWSWorkflowManager\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">" + 
    "<soapenv:Header/>" + 
    "<soapenv:Body>" + 
    "<com:createProjectGroup7_ soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + 
    "<token xsi:type=\"xsd:string\">0000000000</token>" + 
    "<name xsi:type=\"xsd:string\">TEST NEW PROJECT</name>" + 
    "<locales xsi:type=\"data:stringArray\" soapenc:arrayType=\"xsd:string[]\" xmlns:data=\"http://webservices.idiominc.com/data\">" + 
    "<item type=\"xsd:string\">English (United States)</item>" + 
    "<item type=\"xsd:string\">Korean</item>" + 
    "</locales>" + 
    "<attachedFile xsi:type=\"data:stringArray\" soapenc:arrayType=\"xsd:string[]\" xmlns:data=\"http://webservices.idiominc.com/data\">" + 
    "<file type=\"xsd:string\">test.xlsx</file>" + 
    "</attachedFile>" + 
    "<client xsi:type=\"xsd:string\">TEST CLIENT</client>" + 
    "<projectType xsi:type=\"xsd:string\">TEST PROJECT TYPE</projectType>" + 
    "<customAisProperties xsi:type=\"data:stringArray\" soapenc:arrayType=\"xsd:string[]\" xmlns:data=\"http://webservices.idiominc.com/data\"/>" + 
    "</com:createProjectGroup7_>" + 
    "</soapenv:Body>" + 
    "</soapenv:Envelope>").getBytes() 

    var soapcontent = Utilities.newBlob(
    "http://schemas.xmlsoap.org/soap/envelope/" 
    ).getBytes() 

    var firstSoapDime = makeDimeHeader("start", false, [], soapcontent, data) 

    var filecontent = Utilities.newBlob(
    "application/octet-stream" 
    ).getBytes() 

    var lastFileData = makeDimeHeader("finish", false, Utilities.newBlob("test.xlsx").getBytes(), filecontent, fileBytes) 

    var payloadbytes = firstSoapDime.concat(lastFileData) 

    var headers = 
     { 
     "SOAPAction" : "" 
     }; 

    var payload = Utilities.newBlob(payloadbytes).getDataAsString(); 

    var options = 
     { 
     "method" : "post", 
     "headers" : headers, 
     "contentType": contentType, 
     "contentLength": payloadbytes.length, 
     "payload" : payload, 
     "muteHttpExceptions" : true 
     }; 

    var response = UrlFetchApp.fetch("https://<ourdomain>.sdlproducts.com/ws/services/WorkflowWSWorkflowManager", options); 
    Logger.log(payload) 
    Logger.log(response) 
}; 

如果任何人都可以看看我的代码,并发现任何问题,或提出任何其他替代品,我将不胜感激。谢谢。

编辑:我发现在我的原代码中的问题(一个或多个)。

  1. DIME消息中的0x00填充会在数据后发生,而不是之前。
  2. 而不是字符串,我需要有效载荷附加作为字节[]数组。然而,这不能成为一个其中I Concat的2个或更多字节[]数组,因为我认为它们被作为一个正常的阵列处理。所以我通过Utilities.newBlob()。getBytes()来创建一个新的Byte []数组,以防万一。这是通过它的最后一部分。

正确的代码如下。

function makeDimeHeader (position, isChunk, id, contentType, data) { 
    // ref: http://xml.coverpages.org/draft-nielsen-dime-02.txt 
    var bin = "" 

    // version 1 
    bin += "00001" 

    if (position == "start") { 
    bin += "10" 
    } else if (position == "finish") { 
    bin += "01" 
    } else if (position == "middle") { 
    bin += "00" 
    } else if (position == "only") { 
    bin += "11" 
    } else { 
    throw "Error: position must be 'start', 'only', 'middle', or 'finish'" 
    } 

    if (isChunk) { 
    bin += "1" 
    } else { 
    bin += "0" 
    } 

    if (id.constructor !== Array) throw "Error: id must be a byte array" 
    if (contentType.constructor !== Array) throw "Error: contentType must be a byte array" 
    if (data.constructor !== Array) throw "Error: data must be a byte array" 

    var textType = Utilities.newBlob(contentType).getDataAsString() 

    if (textType.slice(0,4) == "http") { 
    bin += "0010" 
    } else if (contentType.length == 0) { 
    bin += "0000" 
    } else { 
    bin += "0001" 
    } 

    // RESERVED 
    bin += "0000" 

    // OPTIONS LENGTH 
    bin += "0000000000000000" 

    bin += ("0000000000000000" + id.length.toString(2)).slice(-16) 

    bin += ("0000000000000000" + contentType.length.toString(2)).slice(-16) 

    bin += ("00000000000000000000000000000000" + data.length.toString(2)).slice(-32) 

    var bytes = [] 
    for (var i = 0; i < bin.length/8; i++) { 
    num = parseInt(bin.slice(i*8,(i*8)+8),2); 
    // Byte[] is an Int8Array, not Uint8Array 
    if (num > 127) num = num - 256 
    bytes.push(num) 
    } 

    bytes = bytes.concat(id) 
    // PADDING TO CLOSEST 4 BYTES 
    if (id.length % 4 != 0) bytes = bytes.concat([0, 0, 0].slice(0, 4 - (id.length % 4))) 

    bytes = bytes.concat(contentType) 
    // PADDING TO CLOSEST 4 BYTES 
    if (contentType.length % 4 != 0) bytes = bytes.concat([0, 0, 0].slice(0, 4 - (contentType.length % 4))) 

    bytes = bytes.concat(data) 
    // PADDING TO CLOSEST 4 BYTES 
    if (data.length % 4 != 0) bytes = bytes.concat([0, 0, 0].slice(0, 4 - (data.length % 4))) 

    return bytes 

} 

function testPost() { 
    var file = UrlFetchApp.fetch("https://.../somedoc.xlsx"); 
    var fileBlob = file.getBlob(); 
    var fileBytes = fileBlob.getBytes(); 

    var contentType = 'application/dime'; 

    var data = Utilities.newBlob(
    "<?xml version=\"1.0\"?>\r\n" + 
    "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:com=\"http://www.idiominc.org/com.idiominc.webservices.WorkflowWSWorkflowManager\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">" + 
    "<soapenv:Header/>" + 
    "<soapenv:Body>" + 
    "<com:createProjectGroup7_ soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + 
    "<token xsi:type=\"xsd:string\">0000000000</token>" + 
    "<name xsi:type=\"xsd:string\">TEST NEW PROJECT</name>" + 
    "<locales xsi:type=\"data:stringArray\" soapenc:arrayType=\"xsd:string[]\" xmlns:data=\"http://webservices.idiominc.com/data\">" + 
    "<item type=\"xsd:string\">English (United States)</item>" + 
    "<item type=\"xsd:string\">Korean</item>" + 
    "</locales>" + 
    "<attachedFile xsi:type=\"data:stringArray\" soapenc:arrayType=\"xsd:string[]\" xmlns:data=\"http://webservices.idiominc.com/data\">" + 
    "<file type=\"xsd:string\">test.xlsx</file>" + 
    "</attachedFile>" + 
    "<client xsi:type=\"xsd:string\">TEST CLIENT</client>" + 
    "<projectType xsi:type=\"xsd:string\">TEST PROJECT TYPE</projectType>" + 
    "<customAisProperties xsi:type=\"data:stringArray\" soapenc:arrayType=\"xsd:string[]\" xmlns:data=\"http://webservices.idiominc.com/data\"/>" + 
    "</com:createProjectGroup7_>" + 
    "</soapenv:Body>" + 
    "</soapenv:Envelope>").getBytes() 

    var soapcontent = Utilities.newBlob(
    "http://schemas.xmlsoap.org/soap/envelope/" 
    ).getBytes() 

    var firstSoapDime = makeDimeHeader("start", false, [], soapcontent, data) 

    var filecontent = Utilities.newBlob(
    "application/octet-stream" 
    ).getBytes() 

    var lastFileData = makeDimeHeader("finish", false, Utilities.newBlob("test.xlsx").getBytes(), filecontent, fileBytes) 

    var payloadbytes = firstSoapDime.concat(lastFileData) 

    var headers = 
     { 
     "SOAPAction" : "" 
     }; 

    var payload = Utilities.newBlob(payloadbytes).getBytes(); 

    var options = 
     { 
     "method" : "post", 
     "headers" : headers, 
     "contentType": contentType, 
     "contentLength": payloadbytes.length, 
     "payload" : payload, 
     "muteHttpExceptions" : true 
     }; 

    var response = UrlFetchApp.fetch("https://<ourdomain>.sdlproducts.com/ws/services/WorkflowWSWorkflowManager", options); 
    Logger.log(payload) 
    Logger.log(response) 
}; 

回答

0

我在编辑中回答了我自己的问题,主OP。