如何使用Coldfusion CFHTTP将JSON数据发布到远程API
我确信我已经完全搞砸了,但是在堆栈溢出用户的帮助下,我得到了这么多,所以非常感谢。
我需要将JSON数据发布到远程API。 显然,由于SOP问题,我不能使用jQuery,而远程API不支持JSONP。
我也不想使用任何类型的代理来解决SOP限制。
根据API文档(http://myemma.com/api-docs/),这是他们期望的数据格式(请求和响应数据以JSON形式传输):
POST https://api.e2ma.net//123/members/add
{
"fields": {
"first_name": "myFirstName"
},
"email": "email@domain.com"
}
这是我迄今为止建立的,但仍然从远程API继续收到“无法解析JSON”错误:
<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>
同样,我肯定会以某种方式破坏我的数据结构,但我不确定我在做什么错误,尤其是关于正确设置“字段”:{“first_name”:“myFirstName”}结构/数组。
您应该将您的请求字符串作为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>
更新10/26/13
对于我最近使用API进行的所有工作,我认为我会更新一个简单的方法来自动化我发现的这个框架。 我已经使用了JSON Util库和Ben Nadel的JSON串行器实用工具CFC的组合,以实现所有退货的更好的序列化一致性。
下面是我如何实施这个的一个例子GIST。
https://gist.github.com/timmaybrown/7226809
当我在项目中过渡到使用持久化实体CFC时,我发现使用我自己的子CFC方法扩展Ben Nadel的序列化CFC方法,该方法使用getComponentMetaData()函数循环执行所有持久化cfc的属性,以构建不同的密钥结构和序列化的外壳。 该方法允许我的api在我的实体中自动继承我的属性名称的外框,并且非常有用。 在reinit上花费一些开销,但非常值得让你的API在你的API中保持一致。
更新9/8/16 Re:我的观点高于一致的套路 。 我已经在新数据库的数据库中使用了不同的列命名约定,所以我不必为这些问题而战。 first_name
而不是firstName
等
更新:2012年9月26日:在我设置的模拟账户申请API密钥后,他们向我发送了一个账户,可能还有account_id。 我将代码放在下面,它的作用就像添加成员的魅力。
让我首先说这个代码没有被测试(见上面的更新)。 我没有MyEmma帐户,显然你必须是account_id的付费客户才能使用API。 这一击! 但是这应该让你真正接近,并可能给你一些封装逻辑的想法,这已经成为我的痴迷。
其次,我意识到这篇文章已经9个月大了,你可能很久以前就已经知道了,或者中了彩票,现在正在运行这个地方。 所以没人会看到这篇文章。 但我自己也在寻找一些答案,并且碰到了它......而且由于制定和解析JSON是我日常生活的一部分,这是我始终需要不断设定自己的一部分。 所以结果是你的问题的一个快速答案,成为深夜,自我服务,迷恋的挑战。 好歹...
...你在用JSON做什么,正在创建客户端嵌套结构。 您有两个键值对(字段和电子邮件)的根结构。 然后,结构“字段”保存一个结构,其中包含您为该电子邮件地址(first_name)发送的键值对。 大概你可以发送更多。
您正在构建嵌套结构。 请记住,一个结构中的关键可以容纳一个结构。 而这些键可以容纳结构等等。 它可以像你想要的那样变得黑暗和讨厌。 但是,所有的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>
请注意,我使用数组符号显式设置结构键名称。 我们必须这样做来控制Coldfusion的情况。 否则,密钥将全部大写......不希望我们需要区分大小写的JavaScript。 这可能是你遇到的问题的一部分。
如果因为案件Emma不理解,那么你会得到你的......
{"error": "Unable to parse JSON request"}
但是,当我们使用数组符号显式设置我们的键名,然后序列化我们的对象时,我们会变得漂亮,漂亮,很棒的时尚JSON ......
{"fields":{"first_name":"myFirstName"},"email":"email@domain.com"}
所以下面,我把我们的http请求发给Emma一个函数。 将Content-Type头部设置为application / json也非常重要,因此浏览器将把它作为对象发送,而不仅仅是文本字符串。 而且我们发送我们的JSON作为我们请求的主体,而不是在一个名为'fields'的表单字段中......希望当您大声说出时,这是有意义的。 这是功能...
<cffunction name="callEmma" access="private" displayname="CallEmma" description="This makes an HTTP REQUEST to MyEmma" returnformat="JSON" output="false" returntype="Any">
<cfargument name="endpoint" required="true" type="string" displayname="EndPoint">
<cfargument name="PUBLIC_API_KEY" required="true" type="string" displayname="PUBLIC_API_KEY">
<cfargument name="PRIVATE_API_KEY" required="true" type="string" displayname="PRIVATE_API_KEY">
<cfargument name="dataFields" required="true" type="struct" displayname="DataFields">
<cfscript>
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
</cfscript>
</cffunction>
然后再一次,这里是我们的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>
然后我们设置变量传递给函数...
<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>
,我通常尽可能地使用<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>
天哪! 我一直在写太多的API ......我显然需要治疗!
你提到的结构
{“fields”:{“first_name”:“myFirstName”},“email”:“email@domain.com”}在这个JSON中,'fields'键的值又是一个JSON所以,你可以像dis
<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>
链接地址: http://www.djcxy.com/p/31193.html
上一篇: How to POST JSON Data to Remote API Using Coldfusion CFHTTP