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) 的要求:
- 一个multipart/form-dataPOST
- 一个名为
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:\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,这似乎是 Adobe 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 ....
我遇到了一个 API,它的文档非常稀少。我已经尝试了所有方法(更多内容见下文),但最终结果是来自第三方服务器的响应:The given path's format is not supported.
这是我对此端点 (POST) 的要求:
- 一个multipart/form-dataPOST
- 一个名为
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:\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,这似乎是 Adobe 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 ....