如何使用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

下一篇: Google Analytics Event not showing up