0

我有一个 SDL 的 WorldServer 实例,我试图通过 SOAP 访问它以创建新项目。

我正在考虑通过 Google Apps 脚本制作一个网络应用程序,用户可以将文件上传到我可以用来发送和制作项目/报价的 blob 中。对于任何不需要附件的命令,我都能让 SOAP 正常工作。但是添加附件会使事情变得复杂。

我已经通过soapui成功地做到了这一点(但是,soapui为我处理了DIME格式,所以我假设我需要使用DIME?),但是当我尝试通过自己手动生成消息来发送相同的SOAP消息时,我收到一个 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)
};

任何人都可以查看我的代码并发现任何问题,或提出任何其他替代方案吗?

4

1 回答 1

0

我在原始代码中发现了问题。

  1. DIME 消息中的 0x00 填充在数据之后,而不是之前。
  2. 我需要将有效负载附加为 Byte[] 数组,而不是字符串。但是,这不能是我连接 2 个或更多 Byte[] 数组的地方,因为我认为它们被视为普通数组。所以我通过 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)
};
于 2016-01-09T12:07:16.950 回答