通过CPI和HTTP适配器将zip文件和表单数据发送到Ariba

2020-08-15 00:06发布

         点击此处--->   EasySAP.com群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)


大家好,

我在CPI中遇到有关HTTP适配器的问题。 该方案是在SFTP服务器中拾取文件,创建带有zip文件的表单数据,然后通过HTTP适配器将其发送到Ariba。

问题是我一直遇到错误状态代码411:要求内容长度。

我尝试手动定义此标头,但没有成功。 将消息发送到另一台主机会确认在CPI发送消息时会自动创建此标头,因此对我来说一定是另一件事。

在浏览博客时,我发现了另一篇有关此问题的文章。 链接在下面:

https://blogs.sap.com/2019/11/14/what-is-form-data-and-how-to-send-it-from-sap-cloud -platform-integration-cpi/

Nick Yang提出了一种解决方案,该解决方案围绕直接在脚本中打开到目标的连接而放弃了使用HTTP适配器的必要性。 但是我试图复制它,但是不断出现错误:

java.lang.NoSuchMethodException:方法的无签名:sun.net.www.http.PosterOutputStream.write()适用于参数类型:(org.apache.camel.converter.stream.InputStreamCache)值:[org .apache.camel.converter.stream.InputStreamCache @ 144c18fd]可能的解决方案:write([B),write(int),write(int),write(int),wait(),wait(long)

我认为这是因为我之前在另一个脚本中创建了表单数据,但之后没有将消息主体转换为字节数组。

有人可以帮我吗?

这是我当前的脚本:

 def消息postZipContentToAriba(消息){
     def messageLog = messageLogFactory.getMessageLog(message)
     def propertiesMap = message.getProperties()
     def headersMap = message.getHeaders()
    //开机自检
     def post = new URL(" Ariba-Network-URL")。openConnection();
     def zipContent = message.getBody()
    
     post.setRequestMethod(" POST")
     post.setDoOutput(true)
     post.setRequestProperty(" Content-Type",headersMap.get(" Content-Type")as String)
     post.getOutputStream()。write(zipContent);
    
     def postRC = post.getResponseCode();
     if(postRC.equals(200)){
         messageLog.addAttachmentAsString("发布结果:",作为字符串的post.getInputStream()。getText(),"文本/纯文本")
     }其他{
         def exceptionMsg =" HTTP" + postRC.toString()+"," + post.getInputStream()。getText()
         抛出新的异常(exceptionMsg作为字符串)
     }
    
     返回讯息
 }


 消息processData(消息){


     返回postZipContentToAriba(消息)
 }
 

在此之前使用的脚本是创建多部分的表单数据:

消息processData(消息消息){
    
    //将多部分设置为主体
     ByteArrayOutputStream outputStream =新的ByteArrayOutputStream()
    
     尝试{
    
         byte []个字节= message.getBody(byte [])
        //构造多部分
         MimeBodyPart bodyPartHead1 =新的MimeBodyPart()
         bodyPartHead1.setText('true')
         bodyPartHead1.setDisposition('form-data; name =" fullload"')
        
         MimeBodyPart bodyPartHead2 =新的MimeBodyPart()
         bodyPartHead2.setText('导入外部系统主数据')
         bodyPartHead2.setDisposition('form-data; name =" event"')
        
         MimeBodyPart bodyPartHead3 =新的MimeBodyPart()
         bodyPartHead3.setText(秘密)
         bodyPartHead3.setDisposition('form-data; name =" sharedsecret"')
        
         MimeBodyPart bodyPartHead4 =新的MimeBodyPart()
         bodyPartHead4.setText(systemId)
         bodyPartHead4.setDisposition('form-data; name =" systemId"')
        
         MimeBodyPart bodyPartHead5 =新的MimeBodyPart()
         bodyPartHead5.setText('加载并删除')
         bodyPartHead5.setDisposition('form-data; name =" Operation"')
        
         MimeBodyPart bodyPartHead6 =新的MimeBodyPart()
         bodyPartHead6.setText('Cloud')
         bodyPartHead6.setDisposition('form-data; name =" clienttype"')
        
         MimeBodyPart bodyPartHead7 =新的MimeBodyPart()
         bodyPartHead7.setText('CPI')
         bodyPartHead7.setDisposition('form-data; name =" clientinfo"')
        
         MimeBodyPart bodyPartHead8 =新的MimeBodyPart()
         bodyPartHead8.setText('1.0.0')
         bodyPartHead8.setDisposition('form-data; name =" clientversion"')
        
        
         MimeBodyPart bodyPart =新的MimeBodyPart()
         ByteArrayDataSource dataSource =新的ByteArrayDataSource(bytes,'application/zip')
         DataHandler byteDataHandler =新的DataHandler(dataSource)
         bodyPart.setDataHandler(byteDataHandler)
         bodyPart.setFileName('content.zip')
         bodyPart.setDisposition('form-data; name =" content"')
    
         MimeMultipart multipart =新的MimeMultipart()
         multipart.addBodyPart(bodyPartHead1)
         multipart.addBodyPart(bodyPartHead2)
         multipart.addBodyPart(bodyPartHead3)
         multipart.addBodyPart(bodyPartHead4)
         multipart.addBodyPart(bodyPartHead5)
         multipart.addBodyPart(bodyPartHead6)
         multipart.addBodyPart(bodyPartHead7)
         multipart.addBodyPart(bodyPartHead8)
         multipart.addBodyPart(bodyPart)
        
         multipart.updateHeaders()
        
         multipart.writeTo(outputStream)
         message.setBody(outputStream)
    
        //用边界设置内容类型
         字符串边界=(new ContentType(multipart.contentType))。getParameter('boundary');
         message.setHeader('Content-Type'," multipart/form-data; boundary = \" $ {boundary} \""")
        
        //计算邮件大小
        //message.setHeader('content-length',message.getBodySize())
    
     } catch(Exception e){
        
     }最后{
         outputStream.close()
     }


     返回讯息
 }
 

谢谢您的问候

JoãoGomes

         点击此处--->   EasySAP.com群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)


大家好,

我在CPI中遇到有关HTTP适配器的问题。 该方案是在SFTP服务器中拾取文件,创建带有zip文件的表单数据,然后通过HTTP适配器将其发送到Ariba。

问题是我一直遇到错误状态代码411:要求内容长度。

我尝试手动定义此标头,但没有成功。 将消息发送到另一台主机会确认在CPI发送消息时会自动创建此标头,因此对我来说一定是另一件事。

在浏览博客时,我发现了另一篇有关此问题的文章。 链接在下面:

https://blogs.sap.com/2019/11/14/what-is-form-data-and-how-to-send-it-from-sap-cloud -platform-integration-cpi/

Nick Yang提出了一种解决方案,该解决方案围绕直接在脚本中打开到目标的连接而放弃了使用HTTP适配器的必要性。 但是我试图复制它,但是不断出现错误:

java.lang.NoSuchMethodException:方法的无签名:sun.net.www.http.PosterOutputStream.write()适用于参数类型:(org.apache.camel.converter.stream.InputStreamCache)值:[org .apache.camel.converter.stream.InputStreamCache @ 144c18fd]可能的解决方案:write([B),write(int),write(int),write(int),wait(),wait(long)

我认为这是因为我之前在另一个脚本中创建了表单数据,但之后没有将消息主体转换为字节数组。

有人可以帮我吗?

这是我当前的脚本:

 def消息postZipContentToAriba(消息){
     def messageLog = messageLogFactory.getMessageLog(message)
     def propertiesMap = message.getProperties()
     def headersMap = message.getHeaders()
    //开机自检
     def post = new URL(" Ariba-Network-URL")。openConnection();
     def zipContent = message.getBody()
    
     post.setRequestMethod(" POST")
     post.setDoOutput(true)
     post.setRequestProperty(" Content-Type",headersMap.get(" Content-Type")as String)
     post.getOutputStream()。write(zipContent);
    
     def postRC = post.getResponseCode();
     if(postRC.equals(200)){
         messageLog.addAttachmentAsString("发布结果:",作为字符串的post.getInputStream()。getText(),"文本/纯文本")
     }其他{
         def exceptionMsg =" HTTP" + postRC.toString()+"," + post.getInputStream()。getText()
         抛出新的异常(exceptionMsg作为字符串)
     }
    
     返回讯息
 }


 消息processData(消息){


     返回postZipContentToAriba(消息)
 }
 

在此之前使用的脚本是创建多部分的表单数据:

消息processData(消息消息){
    
    //将多部分设置为主体
     ByteArrayOutputStream outputStream =新的ByteArrayOutputStream()
    
     尝试{
    
         byte []个字节= message.getBody(byte [])
        //构造多部分
         MimeBodyPart bodyPartHead1 =新的MimeBodyPart()
         bodyPartHead1.setText('true')
         bodyPartHead1.setDisposition('form-data; name =" fullload"')
        
         MimeBodyPart bodyPartHead2 =新的MimeBodyPart()
         bodyPartHead2.setText('导入外部系统主数据')
         bodyPartHead2.setDisposition('form-data; name =" event"')
        
         MimeBodyPart bodyPartHead3 =新的MimeBodyPart()
         bodyPartHead3.setText(秘密)
         bodyPartHead3.setDisposition('form-data; name =" sharedsecret"')
        
         MimeBodyPart bodyPartHead4 =新的MimeBodyPart()
         bodyPartHead4.setText(systemId)
         bodyPartHead4.setDisposition('form-data; name =" systemId"')
        
         MimeBodyPart bodyPartHead5 =新的MimeBodyPart()
         bodyPartHead5.setText('加载并删除')
         bodyPartHead5.setDisposition('form-data; name =" Operation"')
        
         MimeBodyPart bodyPartHead6 =新的MimeBodyPart()
         bodyPartHead6.setText('Cloud')
         bodyPartHead6.setDisposition('form-data; name =" clienttype"')
        
         MimeBodyPart bodyPartHead7 =新的MimeBodyPart()
         bodyPartHead7.setText('CPI')
         bodyPartHead7.setDisposition('form-data; name =" clientinfo"')
        
         MimeBodyPart bodyPartHead8 =新的MimeBodyPart()
         bodyPartHead8.setText('1.0.0')
         bodyPartHead8.setDisposition('form-data; name =" clientversion"')
        
        
         MimeBodyPart bodyPart =新的MimeBodyPart()
         ByteArrayDataSource dataSource =新的ByteArrayDataSource(bytes,'application/zip')
         DataHandler byteDataHandler =新的DataHandler(dataSource)
         bodyPart.setDataHandler(byteDataHandler)
         bodyPart.setFileName('content.zip')
         bodyPart.setDisposition('form-data; name =" content"')
    
         MimeMultipart multipart =新的MimeMultipart()
         multipart.addBodyPart(bodyPartHead1)
         multipart.addBodyPart(bodyPartHead2)
         multipart.addBodyPart(bodyPartHead3)
         multipart.addBodyPart(bodyPartHead4)
         multipart.addBodyPart(bodyPartHead5)
         multipart.addBodyPart(bodyPartHead6)
         multipart.addBodyPart(bodyPartHead7)
         multipart.addBodyPart(bodyPartHead8)
         multipart.addBodyPart(bodyPart)
        
         multipart.updateHeaders()
        
         multipart.writeTo(outputStream)
         message.setBody(outputStream)
    
        //用边界设置内容类型
         字符串边界=(new ContentType(multipart.contentType))。getParameter('boundary');
         message.setHeader('Content-Type'," multipart/form-data; boundary = \" $ {boundary} \""")
        
        //计算邮件大小
        //message.setHeader('content-length',message.getBodySize())
    
     } catch(Exception e){
        
     }最后{
         outputStream.close()
     }


     返回讯息
 }
 

谢谢您的问候

JoãoGomes

付费偷看设置
发送
11条回答
悻福寶寶
1楼 · 2020-08-15 00:52.采纳回答

您好João,

您可以从以下位置更改processData方法中的代码吗?

 message.setBody(outputStream)

 message.setBody(outputStream.toByteArray())

让我知道它的进展。

亲切的问候,

尼克

葫芦娃快救爷爷
2楼-- · 2020-08-15 00:54

你好尼克,

谢谢您的回答。

我设法通过更改以下代码来解决该问题:

 def zipContent = message.getBody()

对此:

 def zipContent = message.getBody(byte [])

我认为它遵循您的处理流程,在这种情况下,是从主体内容中获取字节数组。

感谢您和最诚挚的问候,

JoãoGomes

超级大咸鱼
3楼-- · 2020-08-15 00:59

Hello Joao,

最好在Postman中尝试使用具有确切参数的相同方案,以给出响应以及请求有效负载中缺少的内容(而不只是 拍摄没有更多详细信息的HTTP 400)。

致谢

Sriprasad Shivaram Bhat

95年老男孩
4楼-- · 2020-08-15 00:35

Hello Nick,

感谢您的投入。 我定期使用Postman,但之前从未遇到过HTTP错误代码411。 HTTP适配器错误很麻烦。

实际上,现在我遇到了另一个问题。 客户需要从CPI到Ariba的基于证书的身份验证。 因此,我需要更改postZipContentToAriba函数以在密钥库中使用CPI证书来建立连接,但是我被卡在其中。.

Tong__Ming
5楼-- · 2020-08-15 00:51

您好,João,

也许您已经使用其他工具(例如Sriprasad推荐的邮递员)进行了测试。 就我而言,在开始开发CPI集成程序之前,我在HTML网页下方使用了什么,以观察什么是有效的HTTP POST有效负载,然后尝试从CPI产生完全相同的输出。

 <!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01//EN"" http://www.w3.org/TR/html4/strict.dtd">
 
 <头>
     
     直接访问-文件上传
 
 <身体>
     

直接访问-文件上传

事件:
满载
增量
密码:
客户端类型:
客户信息:
客户端版本:
文件:

亲切的问候,

尼克

天桥码农
6楼-- · 2020-08-15 00:48

你好尼克,

感谢您的快速回复。

我可以确认Ariba Integration Toolkit安全性支持客户端证书登录。 我设法使它能够删除直接调用Ariba的脚本,而改用HTTP适配器。 但是随后返回错误"状态码411:需要内容长度"。我的结论是我无法逃避使用脚本。

最诚挚的问候,

JoãoGomes

lukcy2020
7楼-- · 2020-08-15 00:44

嘿João,

在深入了解CPI使用客户端证书登录功能调用外部服务的功能/可能性之前。

我们需要检查Ariba集成工具包的安全性是否支持客户端证书登录?

您可以按照以下步骤检查设置吗?

干杯。

亲切的问候,

尼克

一周热门 更多>