2012-01-19 119 views
11

我确信我完全搞砸了,但我在Stack Overflow用户的帮助下得到了这么多,所以非常感谢。如何将JSON数据发布到远程API使用Coldfusion CFHTTP

我需要将JSON数据POST到远程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 protected]" 
} 

这是我所建迄今为止,但继续收到“无法解析JSON”从远程API错误:

<cfset fields[name_first]="#SerializeJSON("myFirstName")#" /> 
<cfset form.email="#SerializeJSON("[email protected]")#" /> 

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

我再次肯定重整我的数据结构莫名其妙,但我不确定我在做什么错误,尤其是关于正确设置“fields”:{“first_name”:“myFirstName”} structure/array。

回答

0

鉴于您所提交的数据,你不应该序列化的字符串的方式,只是

value='#serializejson(fields)#' 

从您的评论,这并不为你工作。不幸的是,他们的文件令IMO感到困惑,应该如何发送数据。他们说它应该是一个帖子,但只显示一个json对象。如果从JS使用,但另有混淆,这可能会很有用。

要缩小发生问题的位置,请尝试静态提交信息,例如拿他们的示例代码并粘贴到字段的值中。您应该首先尝试在动态版本之前进行静态尝试。由于区分大小写或其他问题,甚至可能是CF json序列化正在跳闸。

<!--- add email ---> 
<cfhttpparam 
    type="formfield" 
    name="email" 
    value='[email protected]' 
/> 

<!--- 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" ' ---> 
+0

我明白你在说什么,但我仍然得到{“错误”:“无法解析JSON要求“}从API返回。这意味着我没有提交“email”:“email @ domain”。com“或”fields“:{ ”first_name“:”myFirstName“}参数正确地在我上面的例子中,这就是我需要帮助的东西,正确地传递这些JSON字符串 –

0

偶然的时机。我们目前正在解决同一问题。

我们目前正在将我们的CF版本从8更新到9.01,并且有一些使用cfajaxproxy的代码 - 无法在9.01下运行 - 但在CF8中运行良好。

我还未确定(1)该问题的实际根本原因是什么; 如果我有一些时间,我会做更多的工作,以更具体的... 但解决方法是把代码,通过ajax调用在webroot。 (1)它可能是由于使用虚拟目录引起的,或者可能受到CF应用程序框架的影响 - CFIDE脚本被自动插入到文件中 - 并且以预期的JSON格式返回。

我已经记下了一个Adobe的错误。

+0

你正在描述一个不同的问题, 。 –

18

您应该将您的请求字符串作为httpparam类型的正文发送。请求的主体可能与您准备好的结构的整个表单范围类似。一定要使用数组符号来设置结构键,或者在隐式结构创建期间将它们放在“引号”中,以确保当serializeJSON()发生时它们保持正确的大小,否则ColdFusion将使结构键大写。

<cfset stFields = { 
    "fields" = { 
     "first_name" = "myFirstName" 
    }, 
    "email" = "[email protected]" 
}> 

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

更新13年10月26日
对于所有的工作,我最近一直在使用API​​我想我会更新一个简单的方法来自动完成这个外壳我发现这样做。我已经使用了JSON Util库和Ben Nadel的JSON Serializer Utility CFC组合来为所有回报完成更好的序列化一致性。

下面是我如何实现这一点的GIST示例。
https://gist.github.com/timmaybrown/7226809

正如我转移到我的项目中使用持久性实体氟氯化碳,我发现,延长本纳德尔与我自己的孩子CFC方法串行CFC是循环使用getComponentMetaData()功能打造我所有的执着CFC的属性一系列不同的按键和序列化后面的外壳。该方法允许我的api在我的实体中自动继承我的属性名称的外框,并且非常有用。在reinit上花费一些开销,但非常值得让你的API在你的API中保持一致。

更新2016/8/8 回复:我的观点高于一致的套数。我已经在新数据库的数据库中使用了不同的列命名约定,所以我不必为这些问题而战。的first_name代替firstName

+0

如果ColdFusion的序列化过程中出现任何问题,你也可以建立身在一个字符串,如

+1

耶或通过选择使用JSONUtil项目[链接](http://jsonutil.riaforge.org/)修复CF中的一些json序列化问题。有一个严格映射关键区分大小写的选项。此外,在某些情况下使用javaCast('Boolean','true')将确保将其设置为布尔值而非序列化中的字符串。 '' 这将导致在这个JSON字符串 '{”字段“:{”first_name“:”myFirstName“,”is_active“:true},”email“:”[email protected]“} – timbrown

+0

@ user1113083 - 如果这有帮助,您应该将其标记为其他人的正确答案。 – timbrown

8

更新: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 protected]"; 
    variables.dataFields.fields['first_name'] = "myFirstName"; 
    variables.dataFields = serializejson(variables.dataFields); 
</cfscript> 

请注意,我明确地使用数组方式设置结构的键名。我们必须这样做来控制Coldfusion的情况。否则,密钥将全部大写......不希望我们需要区分大小写的JavaScript。这可能是你遇到的问题的一部分。

如果艾玛没有因为案件的了解,那么你会得到你的...

{"error": "Unable to parse JSON request"} 

但是,当我们使用数组表示法明确设置我们的键名,然后序列化我们的对象,我们获得不错,漂亮,好醇”时尚JSON ...

{"fields":{"first_name":"myFirstName"},"email":"[email protected]"} 

所以下面,我把我们的HTTP请求到艾玛的功能。对于也非常重要的是将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 protected]"; 
    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> 
// 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 protected]"; 
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> 

MY GOD!我一直在写太多的API ......我显然需要治疗!

1

你提到

结构{ “田”:{ “FIRST_NAME”: “myFirstName” }, “电子邮件”: “[email protected]” } 在这JSON的“场”键值又是一个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 protected]'); 

</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> 
相关问题