如何使用Coldfusion CFHTTP将JSON数据发布到远程API
我确信我完全搞砸了,但我在其他堆栈溢出用户的帮助下走到了这一步,所以到目前为止,谢谢 我需要将JSON数据发布到远程API。显然,由于SOP问题,我不能使用jQuery,而且远程API不支持JSONP 我也不想使用任何类型的代理来绕过SOP限制 根据API文档(),这是他们期望的数据格式(请求和响应数据作为JSON传输):如何使用Coldfusion CFHTTP将JSON数据发布到远程API,json,coldfusion,cfhttp,Json,Coldfusion,Cfhttp,我确信我完全搞砸了,但我在其他堆栈溢出用户的帮助下走到了这一步,所以到目前为止,谢谢 我需要将JSON数据发布到远程API。显然,由于SOP问题,我不能使用jQuery,而且远程API不支持JSONP 我也不想使用任何类型的代理来绕过SOP限制 根据API文档(),这是他们期望的数据格式(请求和响应数据作为JSON传输): POST https://api.e2ma.net//123/members/add { "fields": { "first_name": "myFirstNa
POST https://api.e2ma.net//123/members/add
{
"fields": {
"first_name": "myFirstName"
},
"email": "email@domain.com"
}
<cfset fields[name_first]="#SerializeJSON( "myFirstName" )#" />
<cfset form.email="#SerializeJSON( "email@domain.com" )#" />
<cfhttp
url="https://api.e2ma.net/123/members/add"
method="POST"
username="username"
password="pssword"
useragent="#CGI.http_user_agent#"
result="objGet">
<!--- add email --->
<cfhttpparam
type="formfield"
name="email"
value='#form.email#'
/>
<!--- add field: name_first --->
<cfhttpparam
type="formfield"
name="fields"
value='#fields[name_first]#'
/>
</cfhttp>
<cfoutput>#objGet.FileContent#</cfoutput>
这是我迄今为止构建的,但仍然从远程API收到“无法解析JSON”错误:
POST https://api.e2ma.net//123/members/add
{
"fields": {
"first_name": "myFirstName"
},
"email": "email@domain.com"
}
<cfset fields[name_first]="#SerializeJSON( "myFirstName" )#" />
<cfset form.email="#SerializeJSON( "email@domain.com" )#" />
<cfhttp
url="https://api.e2ma.net/123/members/add"
method="POST"
username="username"
password="pssword"
useragent="#CGI.http_user_agent#"
result="objGet">
<!--- add email --->
<cfhttpparam
type="formfield"
name="email"
value='#form.email#'
/>
<!--- add field: name_first --->
<cfhttpparam
type="formfield"
name="fields"
value='#fields[name_first]#'
/>
</cfhttp>
<cfoutput>#objGet.FileContent#</cfoutput>
#objGet.FileContent#
同样,我肯定会以某种方式弄乱数据的结构,但我不确定我做错了什么,特别是在正确设置字段方面:{“first_name”:“myFirstName”}结构/数组。考虑到提交数据的方式,不必序列化字符串,只要
value='#serializejson(fields)#'
从你的评论来看,这不适合你。不幸的是,他们的文件让IMO对数据应该如何发送感到困惑。他们说它应该是一个post,但随后只显示一个json对象。如果从JS使用,这可能是有用的,但在其他方面会令人困惑
要缩小问题发生的范围,请尝试静态提交信息,例如,使用示例代码并粘贴到字段的值中。您应该首先尝试在动态版本之前进行静态尝试。甚至可能是由于区分大小写或其他问题,CF json序列化正在使事情陷入困境
<!--- add email --->
<cfhttpparam
type="formfield"
name="email"
value='email@domain.com'
/>
<!--- add field: name_first --->
<cfhttpparam
type="formfield"
name="fields"
value='{ "first_name": "myFirstName" }'
/>
<!--- or if that doesn't work also try value='"first_name": "myFirstName" ' --->
偶然的时机。因为我们目前正在处理同一问题 我们目前正在努力将CF版本从8更新到9.01,并且有一些代码使用了cfajaxproxy——无法在9.01下运行——但在CF8中运行良好 我不确定(1)问题的实际根源是什么; 如果我有时间,我会做一些更具体的工作。。。 但解决方法是将通过ajax调用的代码放在webroot中 (1) 这可能是由于使用虚拟目录造成的,也可能是受到CF应用程序框架的影响(通过该框架,CFIDE脚本会自动插入到文件中),并且会与返回的JSON的预期格式发生冲突
我在Adobe上记录了一个bug。您应该将请求字符串作为httpparam类型的正文发送。请求的主体可能类似于预先准备好的结构的整个表单范围。请确保使用数组表示法设置结构键,或者在隐式结构创建期间将它们放在“引号”中,以确保它们在serializeJSON()发生时保留正确的大小写,否则ColdFusion会将结构键大写
<cfset stFields = {
"fields" = {
"first_name" = "myFirstName"
},
"email" = "email@domain.com"
}>
<cfhttp url="http://api.url.com" method="post" result="httpResp" timeout="60">
<cfhttpparam type="header" name="Content-Type" value="application/json" />
<cfhttpparam type="body" value="#serializeJSON(stFields)#">
</cfhttp>
2013年10月26日更新
对于我最近在API方面所做的所有工作,我想我应该更新一种简单的方法来自动化我发现的这个外壳。我使用了库和Ben Nadel的组合来为所有返回实现更好的序列化一致性
下面是我如何实现此功能的示例要点。当我在我的项目中过渡到使用持久实体CFC时,我发现用我自己的子CFC方法扩展Ben Nadel的序列化程序CFC,该方法使用函数循环我的所有持久CFC属性,以构建不同键的结构和序列化所遵循的大小写。这种方法允许api自动继承实体中属性名的大小写,非常有用。在reinit上有一点开销,但在API中保持套管一致是值得的 2016年8月9日更新
Re:我上面关于一致性套管的观点。对于较新的项目,我倾向于在数据库中使用不同的列命名约定,这样我就不必为这些问题争论太多
first\u name
而不是firstName
等。更新:2012年9月26日:在请求使用我设置的演示帐户的API密钥后,他们向我发送了一个API密钥以及may帐户id。我将代码放在下面,这就像添加成员的魅力一样。
让我首先说,这些代码都没有经过测试(请参阅上面的更新)。我没有MyEmma帐户,显然您必须是帐户id的付费客户才能使用API。太棒了!但这应该会让你真正接近,并可能给你一些封装逻辑的想法,这已经成为我的困扰
第二,我意识到这篇文章已经9个月了,你可能早就明白了,或者中了彩票,现在已经开始经营这个地方了。所以没人会看到这篇文章。但我自己也在寻找答案,然后就遇到了。。。由于制定和解析JSON是我日常生活的一部分,这是我一直需要坚持的事情。所以,对你的问题的快速回答变成了一个深夜的、自私的、强迫性的挑战。无论如何
…您使用JSON所做的是创建客户端嵌套结构。根结构有两个键值对(字段和电子邮件)。然后,结构“fields”包含一个结构,其中包含您为该电子邮件地址(名字)发送的键值对。想必你可以寄更多
您正在构建嵌套结构。请记住,结构中的键可以容纳结构。这些键可以保存结构,等等。它可以变得黑暗和肮脏,因为你想去。但这就是JSON的全部。。。它是一个客户端对象
这是您的数据构建和JSON对象
<cfscript>
variables.dataFields = {};
variables.dataFields['fields'] = {};
variables.dataFields['email'] = "email@domain.com";
variables.dataFields.fields['first_name'] = "myFirstName";
variables.dataFields = serializejson(variables.dataFields);
</cfscript>
但是,当我们使用数组表示法显式地设置键名,然后序列化对象时,我们得到了漂亮的、好的ol’fashion JSON
{"fields":{"first_name":"myFirstName"},"email":"email@domain.com"}
下面,我将我们的http请求放到
<cfscript>
variables.dataFields = {};
variables.dataFields['fields'] = {};
variables.dataFields['email'] = "email@domain.com";
variables.dataFields.fields['first_name'] = "myFirstName";
variables.dataFields = serializejson(variables.dataFields);
</cfscript>
<cfscript>
variables.entryPoint = "/members/add";
variables.PUBLIC_API_KEY= "PUBLIC_API_KEY";
variables.PRIVATE_API_KEY= "PRIVATE_API_KEY";
</cfscript>
<cfscript>
variables.myResponse = callEmma(variables.entryPoint,variables.PUBLIC_API_KEY,variables.PRIVATE_API_KEY,variables.dataFields);
variables.myResponse = deserializejson(variables.myResponse);
</cfscript>
<cfscript>
if(variables.myResponse.added){
writeoutput("Member " & variables.myResponse.member_id & " added!");
}
else{
writeoutput("There was an error adding this member");
}
</cfscript>
<cfscript>
// Function to make our calls to Emma
private any function callEmma(required string endPoint,required string PUBLIC_API_KEY,required string PRIVATE_API_KEY,required string dataFields)
description="This makes an HTTP REQUEST to MyEmma"
displayname="CallEmma"
returnformat="JSON"
output="false"
{
local = {};
local.baseURL = "https://api.e2ma.net/";
local.account_id = "12345";
local.phoneNumber = local.baseURL & local.account_id & arguments.endPoint;
local.connection = new http();
local.connection.setMethod("POST");
local.connection.setUrl(local.phoneNumber);
local.connection.setUsername(arguments.PUBLIC_API_KEY);
local.connection.setPassword(arguments.PRIVATE_API_KEY);
local.connection.setUserAgent(cgi.http_user_agent);
local.connection.addParam(type="header",name="Content-Type", value="application/json");
local.connection.addParam(type="body",value=arguments.dataFields);
local.objGet = local.connection.send().getPrefix();
local.content = local.objGet.filecontent;
return local.content;
}
// Put our data together
variables.dataFields = {};
variables.dataFields['fields'] = {};
variables.dataFields['email'] = "email@domain.com";
variables.dataFields.fields['first_name'] = "myFirstName";
variables.dataFields = serializejson(variables.dataFields);
// Define the parameters for our call to Emma
variables.entryPoint = "/members/add";
variables.PUBLIC_API_KEY= "PUBLIC_API_KEY";
variables.PRIVATE_API_KEY= "PRIVATE_API_KEY";
// Call Emma
variables.myResponse = callEmma(variables.entryPoint,variables.PUBLIC_API_KEY,variables.PRIVATE_API_KEY,variables.dataFields);
variables.myResponse = deserializejson(variables.myResponse);
//Output to browser
if(variables.myResponse.added){
writeoutput("Member " & variables.myResponse.member_id & " added!");
}
else{
writeoutput("There was an error adding this member");
}
</cfscript>
<cfscript>
VARIABLES.postJSON = StructNew();
VARIABLES.nameJSON = StructNew();
StructInsert(VARIABLES.nameJSON, 'first_name','myFirstName');
StructInsert(VARIABLES.postJSON, 'fields',VARIABLES.nameJSON);
StructInsert(VARIABLES.postJSON, 'email','email@domain.com');
</cfscript>
<cfhttp
url="https://api.e2ma.net/123/members/add"
method="POST"
username="username"
password="pssword"
useragent="#CGI.http_user_agent#"
result="objGet">
<cfhttpparam
type="body"
name="field"
value='#SerializeJSON(VARIABLES.postJSON)#'
/>
</cfhttp>
<cfoutput>#objGet.FileContent#</cfoutput>