通过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())

让我知道它的进展。

亲切的问候,

尼克

Nan4612
2楼-- · 2020-08-15 01:02

我已尝试根据您的示例Joao实施客户端证书身份验证。 我不断收到未经授权的401。

我已经在Ariba端进行了配置更改以进行证书身份验证,并粘贴了CPI证书。

callcenter油条
3楼-- · 2020-08-15 00:36

嗨João,

因此,这是我之前遇到的HTTP适配器"状态代码411:要求内容长度"中的问题。 您可以向CPI小组索取支持票,以在HTTP适配器中解决此问题。

我以前没有使用Groovy脚本完成客户端证书登录,但是以后可以查看。

亲切的问候,

尼克

微wx笑
4楼-- · 2020-08-15 00:56

大家好,

通过一些搜索和完善的调整,我能够在Java和groovy之间混合使用客户端证书身份验证,从而更改了用于共享秘密身份验证的已使用脚本。

在这里:

导入com.sap.gateway.ip.core.customdev.util.Message
 导入javax.activation.DataHandler
 导入javax.mail.internet.ContentType
 导入javax.mail.internet.MimeBodyPart
 导入javax.mail.internet.MimeMultipart
 导入javax.mail.util.ByteArrayDataSource
 导入java.nio.charset.StandardCharsets
 导入java.util.Base64;
 导入javax.net.ssl.KeyManager;
 导入javax.net.ssl.KeyManagerFactory;
 导入javax.net.ssl.SSLContext;
 导入javax.net.ssl.SSLSocketFactory;
 导入javax.net.ssl.TrustManager;
 导入javax.net.ssl.TrustManagerFactory;
 导入javax.net.ssl.HttpsURLConnection;
 导入java.net.URL;
 导入java.net.URLConnection;

 def消息postZipContentToAriba(消息){
    
    //我们与我们的信任/密钥管理者一起构建SSLContext
     SSLContext sslContext = SSLContext.getInstance(" TLS");
     com.sap.it.api.keystore.KeystoreService ks = com.sap.it.api.ITApiFactory.getApi(com.sap.it.api.keystore.KeystoreService.class,null)
     如果(ks!= null){
        //获取SSLContext的相关对象
         KeyManager [] km = ks.getKeyManagers();
         TrustManager [] tm = ks.getTrustManagers();
        //初始化上下文
         sslContext.init(km,tm,null);
     }
    
     SSLSocketFactory sslSf = sslContext.getSocketFactory();
    
    //准备要连接的URL
     def messageLog = messageLogFactory.getMessageLog(message)
     def propertiesMap = message.getProperties()
     def headersMap = message.getHeaders()
    
     字符串aribaAddress = propertiesMap.get(" aribaAddress")
     字符串queryParameters = propertiesMap.get(" queryParameters")
    
    //我们准备一个URLConnection
     URL url =新URL(aribaAddress +"?" + queryParameters);
     URLConnection urlConnection = url.openConnection();
    //在实际打开套接字之前,我们会影响SSLSocketFactory
     HttpsURLConnection httpsUrlConnection =(HttpsURLConnection)urlConnection;
     httpsUrlConnection.setSSLSocketFactory(sslSf);


    //开机自检
     def zipContent = message.getBody(byte [])
     httpsUrlConnection.setRequestMethod(" POST")
     httpsUrlConnection.setDoOutput(true)
     httpsUrlConnection.setRequestProperty(" Content-Type",headersMap.get(" Content-Type")作为字符串)
     httpsUrlConnection.getOutputStream()。write(zipContent);
    
     def postRC = httpsUrlConnection.getResponseCode();
     if(postRC.equals(200)){
         messageLog.addAttachmentAsString("发布结果:",作为字符串的httpsUrlConnection.getInputStream()。getText(),"文本/纯文本")
     }其他{
         def exceptionMsg =" HTTP" + postRC.toString()+"," + httpsUrlConnection.getInputStream()。getText()
         抛出新的异常(exceptionMsg作为字符串)
     }
    
     返回讯息
 }


 消息processData(消息){


     返回postZipContentToAriba(消息)
 }
 

我希望它会对尝试这种方法的任何人有所帮助!
最诚挚的问候,

JoãoGomes

Alawn_Xu
5楼-- · 2020-08-15 00:56

嗨João,

很高兴看到您找出可行的脚本。

这里有趣的是,在准备sslcontext时,我没有看到您指定别名并放入凭据。 如果代码可以正常工作,就可以了。

干杯。

亲切的问候,

尼克

一周热门 更多>