Coldfusion cfhttp multipartType -我如何在同一请求中发送JSON和文件?



我面对的是一个文档非常稀少的API。我已经尝试了所有方法(下面有更多),但最终结果是来自第三方服务器的响应:The given path's format is not supported.

下面是我对这个端点(POST)的要求:

  • multipart/form-data POST
  • 一个名为json的表单字段,带有JSON字符串
  • 文件名为file

这是"文档"我得到了(为了清晰起见简化了JSON)…

---------------------------acebdf13572468
Content-Disposition: form-data; name="json"
Content-Type: application/json
{
"Foo": "bar",
"Bar": "foo"
}
---------------------------acebdf13572468
Content-Disposition: form-data; name="file"; filename="api.jpg"
Content-Type: image/jpeg
<@INCLUDE *C:UsersjohnSmithPicturesapi.jpg*@>
---------------------------acebdf13572468--

我在服务器上设置了一个页面,所以不是发布到他们的API,而是发布到我的页面,这样我就可以看到正在发布的数据。我这样做是因为尽管我尽了最大的努力,我还是不能让第三方检索日志来告诉我他们在他们那端看到了什么。

下面是产生与他们的"代码示例"最相似的输出的代码。我粘贴了:

<cfhttp method="POST" url="#ApiUrl#" result="CfhttpResult" timeout="30" multipart="yes" multipartType="related">
<cfhttpparam type="header" name="subscription-key" value="#SubscriptionKey#" />
<cfhttpparam type="header" name="developer-key" value="#DeveloperKey#" />
<cfhttpparam type="formField" name="json" value="#Payload#">
<cfhttpparam type="file" name="file" file="#FilePath#" mimetype="#FileMimeType#">
</cfhttp>

这是在我的服务器而不是API上发布到页面的结果:

-------------------------------7d0d117230764
Content-Disposition: form-data; name="json"
Content-Type: text/plain; charset=UTF-8
{"Foo": "bar","Bar": "foo"}
-------------------------------7d0d117230764
Content-Disposition: form-data; name="file"; filename="E:WEBROOTmywebsite.comwwwrootcontentfile20225test_024808PM.png"
Content-Type: image/png
�PNG


IHDR   �   �     X' �  
�iCCPICC Profile  H��� TS� �Ͻ鍒�k轷 RB �  D%$�� CBP�+�#8���` ��*8*EƂX�0(6� dPQ��  *� 
(loads more binary data here)

对我来说,这看起来很正确,也符合他们的例子,但我仍然得到同样的回应。

multipartType属性似乎是关键,这是我写了14年ColdFusion之后没有使用过的东西。似乎它添加了必要的头,并将文件从JSON中分离出来。

有人能发现我可能忽略的东西吗?我迫切需要另一双眼睛和一个健康检查。

引起我注意的一个区别是示例filename值只包含名称和扩展名:

Content-Disposition: form-data; name="file"; filename="api.jpg"

而来自cfhttp的则包含一个目录。(顺便说一句,这似乎是Adobe ColdFusion的一个特点。在Lucee下执行相同的代码,包含目录。由于POST已经包含了文件二进制,我正在努力找到一个很好的理由,为什么cfhttp应该发送完整路径到远程url。在我看来,这不是一个很好的安全选择,暴露本地文件路径…)

Content-Disposition: form-data; name="file"; filename="E:WEBROOTmywebsite.comwwwrootcontentfile20225test_024808PM.png"

无论如何,根据错误消息,我猜测接收端正在使用c#和Path。组合以构造上传文件的路径。在处理文件时可能会崩溃,因为filename

值包含一个不期望的目录路径?只是为了笑,尝试这个线程的建议,建议使用Apache的HttpClient来执行POST而不是cfhttp。尝试一下,看看API响应是否不同。以下是基于您的字段的更新版本:

<cfscript>
// Note: Using port 8888 for Fiddler
postURI = "http://127.0.0.1:8888/dev/testPage.cfm";
filePath = "c:tempsample_plan.png";
payload = serializeJSON({"something" : "here"});

method = createObject("java", "org.apache.commons.httpclient.methods.PostMethod").init( postURI );

try {
// add custom headers
method.addRequestHeader("subscription-key", "keyvalue-123");
method.addRequestHeader("developer-key", "devkey-456");

// add "json" form field
jsonPart = createObject("java", "org.apache.commons.httpclient.methods.multipart.StringPart").init(
"json"
, payload
);

// Optional, use if you need to set the content-type to "application/json"
// jsonPart.setContentType("application/json");
// add "file" field
filePart = createObject( "java", "org.apache.commons.httpclient.methods.multipart.FilePart").init(
"file"  
, "myFile.png"
, createObject( "java", "java.io.File").init( filePath )
);
// construct request data     
requestEntity = createObject( "java", "org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity").init(
[ jsonPart, filePart  ]
, method.getParams()
);

method.setRequestEntity( requestEntity );

// submit and display response
status = createObject('java', 'org.apache.commons.httpclient.HttpClient').init().executeMethod( method );
body = method.getResponseBody();
writeOutput( charsetEncode(body, "utf-8"));

}
finally {
method.releaseConnection();
}
</cfscript>

由于GetHTTPRequestData()并不总是提供完整的请求数据,下面是来自Fiddler的原始响应。它似乎包含正确的字段和标题:

POST /dev/testPage.cfm HTTP/1.1
subscription-key: keyvalue-123
developer-key: devkey-456
User-Agent: Jakarta Commons-HttpClient/3.1
Host: 127.0.0.1:8888
Content-Length: 100628
Content-Type: multipart/form-data; boundary=f5H4CnWAvpMQPoK_X7J2YKmgiN_gAnn

--f5H4CnWAvpMQPoK_X7J2YKmgiN_gAnn
Content-Disposition: form-data; name="json"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit

{"something":"here"}
--f5H4CnWAvpMQPoK_X7J2YKmgiN_gAnn
Content-Disposition: form-data; name="file"; filename="myFile.png"
Content-Type: application/octet-stream; charset=ISO-8859-1
Content-Transfer-Encoding: binary

�PNG
... more binary data ....

最新更新