2012-01-19 172 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> 
相關問題