15

私はこれを完全に台無しにしていると確信していますが、仲間のスタックオーバーフローユーザーの助けを借りてここまで来ました。

JSON データをリモート API に POST する必要があります。明らかに、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" }構造/配列。

4

5 に答える 5

29

要求文字列を本文の 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>

2013 年 10 月 26 日の更新
最近 API を使って行ってきたすべての作業について、見つけたこのケーシングを自動化する簡単な方法を更新しようと思いました。JSON Utilライブラリと Ben Nadel のJSON Serializer Utility CFCを組み合わせて使用​​し、すべてのリターンのシリアライゼーションの一貫性を大幅に向上させました。

以下は、これをどのように実装したかの GIST の例です。
https://gist.github.com/timmaybrown/7226809

プロジェクトで永続エンティティ CFC を使用するようになったとき、Ben Nadel のシリアライザー CFC を独自の子 CFC メソッドで拡張し、getComponentMetaData()関数を使用して永続 CFC のすべてのプロパティをループし、個別のキーの構造を構築することに気付きました。そして連載用のケーシング。このアプローチにより、API はエンティティ内のプロパティ名の大文字と小文字を自動的に継承でき、非常に便利です。reinit には多少のオーバーヘッドがかかりますが、API で大文字と小文字の一貫性を維持する価値があります。

2016 年 9 月 8 日の更新 Re: 大文字と小文字の一貫性に関する上記のポイント。新しいプロジェクトのデータベースでは、別の列の命名規則を使用する傾向にあるので、これらの問題の多くと戦う必要はありません。などfirst_nameの代わりにfirstName

于 2012-02-04T17:44:45.837 に答える
10

更新: 2012 年 9 月 26 日: 私がセットアップしたデモ アカウントで API キーをリクエストしたところ、5 月の account_id と共に 1 つが送られてきました。以下にコードをドロップすると、メンバーを追加するための魅力のように機能しました。

まず、このコードはテストされていません (上記の更新を参照)。私は MyEmma アカウントを持っていません。API を使用するには、account_id に対して有料の顧客である必要があるようです。それが吹く!しかし、これはあなたを本当に近づけるはずであり、私の強迫観念になっているロジックをカプセル化するためのいくつかのアイデアを与えるかもしれません.

第二に、この投稿は 9 か月前のものであり、おそらく長い間それを理解しているか、宝くじに当選してその場所を運営していることに気づきました。したがって、誰もこの投稿を見ることさえありません。しかし、私は自分でいくつかの答えを探していて、偶然見つけました... JSON の作成と解析は私の日常生活の一部であるため、これは常に自分自身をまっすぐに設定し続ける必要があるものです. それで、あなたの質問への素早い答えであることが判明したのは、深夜の自己奉仕的で強迫的な挑戦になりました. とにかく...

...JSON で行っていることは、クライアント側のネストされた構造を作成することです。2 つのキーと値のペア (フィールドと電子メール) を持つルート構造があります。次に、構造体 'fields' は、その電子メール アドレス (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 には望ましくありません。これは、あなたが抱えている問題の一部である可能性があります。

エマが大文字と小文字を区別して理解できない場合、あなたはあなたの...

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

しかし、配列表記を使用してキー名を明示的に設定し、オブジェクトをシリアル化すると、素敵できれいな、古き良きファッションの JSON が得られます...

{"fields":{"first_name":"myFirstName"},"email":"email@domain.com"}

以下では、Emma への http リクエストを関数に入れています。Content-Type ヘッダーを application/json として設定することも非常に重要です。これにより、ブラウザはそれを単なるテキスト文字列ではなくオブジェクトとして送信します。そして、「フィールド」と呼ばれるフォーム フィールドではなく、JSON をリクエストの本文として送信しています。ここに機能があります...

<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>
// 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 を書いてきました...明らかに治療が必要です!

于 2012-09-25T07:55:09.943 に答える
1

あなたが言及した構造

{ "fields": { "first_name": "myFirstName" }, "email": "email@domain.com" } この JSON では、「fields」のキー値も JSON です。したがって、次のようにできます。

<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>
于 2014-08-26T11:36:54.570 に答える
0

データを送信する方法を考えると、文字列をシリアル化する必要はありません。

value='#serializejson(fields)#'

あなたのコメントから、それはあなたにとってうまくいきませんでした。残念ながら、彼らのドキュメントは、データの送信方法に関して IMO を混乱させています。彼らはそれが投稿であるべきだと言っていますが、jsonオブジェクトしか表示されません。JS から使用する場合は便利かもしれませんが、それ以外の場合は混乱します。

問題が発生している場所を絞り込むには、情報を静的に送信してみてください。たとえば、サンプル コードをフィールドの値に貼り付けます。最初に、動的バージョンの前に静的試行を取得するようにしてください。大文字と小文字の区別やその他の問題が原因で、CF json シリアライゼーションが問題を引き起こしている可能性さえあります。

<!--- add email --->
<cfhttpparam
  type="formfield"
  name="email"
  value='email@domain.com'
/>

<!--- 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" ' --->
于 2012-01-20T01:11:44.253 に答える
0

たまたまのタイミング。その点で、私たちは現在同じ問題に取り組んでいます。

現在、CF バージョンを 8 から 9.01 に更新する作業を行っており、cfajaxproxy を使用するコードがいくつかあります (9.01 では実行できません) が、CF8 では正常に動作します。

(1) 問題の実際の根本原因が何であるかについては未定です。時間があれば、より具体的にするためにさらに作業を行います... しかし、回避策は、ajax を介して呼び出されているコードを webroot に配置することです。

(1) 仮想ディレクトリの使用が原因である可能性があります。または、CF アプリケーション フレームワーク (CFIDE スクリプトが自動的にファイルに挿入される) によって影響を受け、返される JSON の予期される形式が混乱する可能性があります。

Adobe のバグを記録しました。

于 2012-01-20T01:17:58.263 に答える