2012-01-19 50 views
11

Tôi chắc chắn rằng tôi hoàn toàn botching này nhưng tôi đã nhận điều này đến nay với sự giúp đỡ của người sử dụng Stack Overflow đồng, vì vậy cảm ơn cho đến nay.Làm thế nào để POST dữ liệu JSON để API từ xa bằng cách sử dụng Coldfusion CFHTTP

Tôi cần POST dữ liệu JSON vào một API từ xa. Rõ ràng là tôi không thể sử dụng jQuery do các vấn đề SOP và API từ xa không hỗ trợ JSONP.

Tôi cũng không muốn sử dụng bất kỳ loại proxy nào để tránh các giới hạn của SOP.

mỗi tài liệu API (http://myemma.com/api-docs/), đây là định dạng của dữ liệu mà họ mong đợi (yêu cầu và dữ liệu đáp ứng được chuyển giao như JSON):

POST https://api.e2ma.net//123/members/add 
{ 
    "fields": { 
    "first_name": "myFirstName" 
    }, 
    "email": "[email protected]" 
} 

Và đây là những gì tôi đã xây dựng vậy, đến nay nhưng vẫn tiếp tục nhận được "không có khả năng phân tích cú pháp JSON" lỗi từ API từ xa:

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

Một lần nữa, tôi chắc chắn mangling cấu trúc của dữ liệu của tôi bằng cách nào đó, nhưng Tôi không chắc mình đang làm gì sai, đặc biệt là việc đặt đúng các trường "": {"first_name": "myFirstName"} cấu trúc/mảng.

Trả lời

0

Với cách bạn đang gửi dữ liệu mà bạn không cần phải sắp đặt từng chuỗi, chỉ

value='#serializejson(fields)#' 

Từ nhận xét của bạn, điều đó không làm việc cho bạn. Thật không may, tài liệu của họ khiến IMO khó hiểu về cách gửi dữ liệu. Họ nói rằng nó phải là một bài nhưng sau đó chỉ hiển thị một đối tượng json. Có lẽ đó là hữu ích nếu sử dụng từ JS nhưng khó hiểu khác.

Để thu hẹp nơi xảy ra sự cố, hãy thử gửi thông tin tĩnh, ví dụ lấy mã mẫu và dán vào giá trị của các trường. Trước tiên, bạn nên cố gắng để có được một nỗ lực tĩnh trước khi một phiên bản năng động. Nó thậm chí có thể là serialization json CF là vấp những thứ lên do trường hợp nhạy cảm hoặc các vấn đề khác.

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

tôi hiểu những gì bạn đang nói, nhưng tôi vẫn đang nhận được { "lỗi": "Không thể phân tích JSON yêu cầu"} trở lại từ API. Điều này có nghĩa là tôi không gửi "email": "email @ domain.com "hoặc" trường ": { thông số" first_name ":" myFirstName "} chính xác trong ví dụ trên của tôi. Đó là những gì tôi cần trợ giúp. Hãy chuyển đúng các chuỗi JSON đó. –

0

Thời gian ngẫu nhiên. Trong đó chúng tôi hiện đang làm việc thông qua cùng một vấn đề.

Chúng tôi hiện đang làm việc để cập nhật phiên bản CF của chúng tôi từ 8 đến 9.01 và có một số mã sử dụng cfajaxproxy - không chạy được dưới 9,01 - nhưng hoạt động tốt trong CF8.

Tôi chưa quyết định (1) về nguyên nhân gốc thực sự của vấn đề là gì; Nếu tôi có thời gian, tôi sẽ thực hiện thêm một số công việc cụ thể hơn ... nhưng giải pháp thay thế là đặt mã được gọi qua ajax trong webroot.

(1) có thể do việc sử dụng các thư mục ảo, hoặc có thể do khung ứng dụng CF thực hiện - nhờ đó các kịch bản CFIDE được chèn tự động vào các tệp - và lộn xộn với định dạng được mong đợi của JSON.

Tôi đã đăng lỗi với Adobe.

+0

Bạn đang mô tả một vấn đề khác nhưng tôi đánh giá cao đầu vào –

18

Bạn nên gửi chuỗi yêu cầu của mình làm loại nội dung httpparam. Phần thân của yêu cầu có thể giống như toàn bộ phạm vi hình dạng của cấu trúc được dựng sẵn của bạn.Hãy chắc chắn sử dụng ký hiệu mảng để thiết lập khóa cấu trúc của bạn hoặc đặt chúng trong "dấu ngoặc kép" trong khi tạo cấu trúc ngầm để đảm bảo chúng giữ nguyên vỏ bọc thích hợp của chúng khi serializeJSON() diễn ra nếu không ColdFusion sẽ viết hoa các phím cấu trúc.

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

Cập nhật 10/26/13
Đối với tất cả công việc tôi đã làm thời gian gần đây với các API tôi nghĩ rằng tôi muốn cập nhật một cách dễ dàng để tự động vỏ này mà tôi đã tìm thấy. Tôi đã sử dụng một sự kết hợp của thư viện JSON Util và Ben Nadel's JSON Serializer Utility CFC để đạt được tính nhất quán tuần tự tốt hơn cho tất cả các lợi nhuận.

Dưới đây là ví dụ về GIST về cách tôi đã triển khai điều này.
https://gist.github.com/timmaybrown/7226809

Như tôi đã chuyển sang sử dụng thực thể dai dẳng CFC trong các dự án của tôi, tôi đã tìm thấy rằng việc mở rộng CFC serializer Ben Nadel với phương pháp CFC con của riêng tôi mà vòng tất cả các thuộc tính CFC dai dẳng của tôi bằng cách sử dụng getComponentMetaData() chức năng để xây dựng một cấu trúc của các phím riêng biệt và vỏ bọc cho serialization để làm theo. Cách tiếp cận này cho phép api của tôi kế thừa tự động vỏ các tên thuộc tính của tôi trong các thực thể của tôi và rất hữu ích. Một chút chi phí trên reinit, nhưng cũng có giá trị nó để giữ cho vỏ của bạn phù hợp trong API của bạn.

Cập nhật 9/8/16 : điểm của tôi ở trên về vỏ đồng nhất. Tôi có xu hướng hướng tới một quy ước đặt tên cột khác trong cơ sở dữ liệu của tôi cho các dự án mới hơn vì vậy tôi không phải chiến đấu với rất nhiều vấn đề này. first_name thay vì firstName v.v.

+0

Nếu coldfusion trình bày bất kỳ vấn đề nào trong quá trình serialization, bạn cũng có thể xây dựng phần thân trong một chuỗi như

+1

vâng hoặc sửa một số vấn đề về tuần tự hóa json trong CF bằng cách tùy ý sử dụng dự án JSONUtil [link] (http://jsonutil.riaforge.org/). có một tùy chọn để ánh xạ nghiêm ngặt đối với độ nhạy trường hợp khóa. Ngoài ra bạn trong một số trường hợp sử dụng javaCast ('Boolean', 'true') sẽ đảm bảo được thiết lập như là một boolean chứ không phải là một chuỗi trong serialization. '' Điều này sẽ dẫn đến chuỗi json này '{" các trường ": {" first_name ":" myFirstName "," is_active ": true}," email ":" [email protected] "}' – timbrown

+0

@ user1113083 - nếu điều này hữu ích, bạn nên đánh dấu câu trả lời này là câu trả lời đúng cho người khác . – timbrown

8

Cập nhật: 9/26/2012: Sau khi yêu cầu khóa API với tài khoản demo tôi đã thiết lập, họ đã gửi cho tôi cùng với tài khoản có thể account_id. Tôi đã bỏ mã bên dưới và nó hoạt động như một sự quyến rũ để thêm một thành viên.

Hãy để tôi bắt đầu bằng cách nói rằng không có mã nào trong số này được kiểm tra (xem phần cập nhật ở trên). Tôi không có tài khoản MyEmma và dường như bạn phải là khách hàng thanh toán cho tài khoản_id để sử dụng API. Điều đó thổi! Nhưng điều này sẽ giúp bạn thực sự gần gũi và có thể cung cấp cho bạn một số ý tưởng để đóng gói logic, điều này đã trở thành nỗi ám ảnh của tôi.

Thứ hai, tôi nhận thấy bài đăng này đã được 9 tháng tuổi và bạn có thể đã tìm ra nó hoặc giành được xổ số và đang chạy địa điểm ngay bây giờ. Vì vậy, không ai có thể nhìn thấy bài đăng này. Nhưng tôi đang tìm kiếm một số câu trả lời cho bản thân và chạy qua nó ... và kể từ khi xây dựng và phân tích cú pháp JSON là một phần trong cuộc sống hàng ngày của tôi, đây là điều tôi luôn cần phải tiếp tục. Vì vậy, những gì hóa ra là một câu trả lời nhanh cho câu hỏi của bạn, đã trở thành một đêm khuya, tự phục vụ, thách thức ám ảnh. Ở bất kỳ mức giá nào ...

... những gì bạn đang làm với JSON, đang tạo cấu trúc lồng nhau phía khách hàng. Bạn có cấu trúc gốc với hai cặp khóa-giá trị (trường và email). Sau đó, cấu trúc 'các trường' nắm giữ một cấu trúc với cặp khóa-giá trị mà bạn đang gửi qua cho địa chỉ email đó (first_name). Có lẽ bạn có thể gửi thêm.

Bạn đang xây dựng các cấu trúc lồng nhau. Hãy nhớ rằng một khóa trong cấu trúc có thể chứa một cấu trúc. Và những chìa khóa đó có thể giữ cấu trúc, vân vân. Nó có thể trở nên tối và khó chịu như bạn muốn. Nhưng đó là tất cả JSON là ... đó là một đối tượng phía khách hàng.

Vì vậy, đây là công cụ xây dựng dữ liệu và JSON của bạn ...

<cfscript> 
    variables.dataFields = {}; 
    variables.dataFields['fields'] = {}; 
    variables.dataFields['email'] = "[email protected]"; 
    variables.dataFields.fields['first_name'] = "myFirstName"; 
    variables.dataFields = serializejson(variables.dataFields); 
</cfscript> 

Lưu ý rằng tôi đang thiết lập một cách rõ ràng cấu trúc tên quan trọng với ký hiệu mảng. Chúng ta phải làm điều này để kiểm soát trường hợp với Coldfusion. Nếu không, các phím sẽ nằm trong tất cả các mũ ... không muốn chúng tôi muốn JavaScript có phân biệt chữ hoa chữ thường. Đây có thể là một phần của vấn đề bạn đang gặp phải.

Nếu Emma không hiểu vì trường hợp, sau đó bạn sẽ nhận được của bạn ...

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

Nhưng khi chúng ta rõ ràng thiết lập tên chủ chốt của chúng tôi sử dụng ký hiệu mảng, và sau đó serialize đối tượng của chúng tôi, chúng tôi nhận được tốt đẹp và đẹp, tốt thời trang ol 'JSON ...

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

Vì vậy, dưới đây, tôi đặt yêu cầu http của chúng tôi để Emma trong một chức năng. Một điều rất quan trọng là đặt tiêu đề Kiểu nội dung là application/json, do đó trình duyệt sẽ gửi nó làm đối tượng chứ không phải chỉ là chuỗi văn bản. Và chúng tôi đang gửi JSON của chúng tôi làm phần thân yêu cầu của chúng tôi, không có trong trường biểu mẫu được gọi là 'trường' ... hy vọng điều đó có ý nghĩa khi bạn nói to. Dưới đây là các chức năng ...

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

Sau đó, một lần nữa, đây là xây dựng của chúng tôi JSON (cấu trúc lồng nhau) ...

<cfscript> 
    variables.dataFields = {}; 
    variables.dataFields['fields'] = {}; 
    variables.dataFields['email'] = "[email protected]"; 
    variables.dataFields.fields['first_name'] = "myFirstName"; 
    variables.dataFields = serializejson(variables.dataFields); 
</cfscript> 

Sau đó, chúng tôi thiết lập các biến để vượt qua các chức năng ...

<cfscript> 
    variables.entryPoint = "/members/add"; 
    variables.PUBLIC_API_KEY= "PUBLIC_API_KEY"; 
    variables.PRIVATE_API_KEY= "PRIVATE_API_KEY"; 
</cfscript> 

Sau đó, thực hiện cuộc gọi điện thoại ...

<cfscript> 
    variables.myResponse = callEmma(variables.entryPoint,variables.PUBLIC_API_KEY,variables.PRIVATE_API_KEY,variables.dataFields); 
    variables.myResponse = deserializejson(variables.myResponse); 
</cfscript> 

Sau đó chúng tôi nhận phản hồi của chúng tôi, deserialize nó, và đầu ra các biến tuy nhiên chúng tôi muốn.

<cfscript> 
    if(variables.myResponse.added){ 
     writeoutput("Member " & variables.myResponse.member_id & " added!"); 
    } 
    else{ 
     writeoutput("There was an error adding this member"); 
    } 
</cfscript> 

Ngoài ra, tôi thường sử dụng <cfscript> nhiều nhất có thể. Nó dễ đọc hơn và nó khiến tôi cảm thấy thông minh hơn tôi thực sự. Vì vậy, khi chúng tôi đặt nó tất cả cùng nhau, cho cắt-và-dán, chúng tôi có điều này ...

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

Chúa ơi! Tôi đã viết WAY quá nhiều API ... Tôi rõ ràng cần điều trị!

1

Cấu trúc bạn đã đề cập

{ "lĩnh vực": { "first_name": "myFirstName" }, "email": "[email protected]" } Trong này JSON cho giá trị then chốt 'lĩnh vực' một lần nữa là một JSON vì vậy, bạn có thể đi như 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> 
Các vấn đề liên quan