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

Coldfusion cfhttp multipartType - How do I send JSON and file in same request?

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

这是我对此端点 (POST) 的要求:

这是我得到的“文档”(为清楚起见简化了 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:\Users\johnSmith\Pictures\api.jpg*@>
---------------------------acebdf13572468--

我在我的服务器上设置了一个页面,所以我 post 到我的页面,而不是 post 到他们的 API,所以我可以看到正在 post编辑。我这样做是因为尽管我尽了最大努力,但我无法让第 3 方检索日志来告诉我他们看到了什么。

这是生成与我在上面粘贴的“代码示例”最相似的输出的代码:

<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>

这是 post 访问我服务器页面而不是 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:\WEBROOT\mywebsite.com\wwwroot\content\file22\test_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 属性似乎是关键,这是我在编写 ColdFusion 约 14 年后从未使用过的东西。似乎它添加了必要的 headers 并将文件与 JSON.

分开

任何人都可以发现我可能忽略的东西吗?我迫切需要另一对眼球和健全性检查。

我突然想到的一个区别是示例 filename 值仅包含名称和扩展名:

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

而来自 cfhttp 的那个也包含一个目录。 (FWIW,这似乎是 Adob​​e ColdFusion 的一个特点。在 Lucee 下执行相同的代码 not 包含目录。因为 POST 已经包含文件二进制文件我是努力寻找 cfhttp 应该将完整路径发送到远程 url 的充分理由。IMO 不是一个很好的安全选择,暴露本地文件路径...)

Content-Disposition: form-data; name="file"; filename="E:\WEBROOT\mywebsite.com\wwwroot\content\file22\test_024808PM.png"

总之,根据错误信息我猜测接收端正在使用C#和Path.Combine构建上传文件的路径。它可能会在处理您的文件时崩溃,因为 filename 值包含一个不在预期范围内的目录路径?

只是为了开心,尝试 this thread which suggests using the Apache's HttpClient 中的建议来执行 POST 而不是 cfhttp。试试看 API 响应是否不同。这是基于您的字段的更新版本:

<cfscript>
    // Note: Using port 8888 for Fiddler
    postURI = "http://127.0.0.1:8888/dev/testPage.cfm";
    filePath = "c:\temp\sample_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() doesn't always provide the unadulterated request data, here's the raw response from Fiddler。它似乎包含正确的字段和 headers:

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 ....