ApexからコールアウトでPOST送信する

apexクラスからコールアウトを使って外部APIにPOST送信してみた。
ファイルも一緒に送信する。

※追記
実際にこの内容で送信してみると、壊れたファイルが送信されてしまいます。
原因を調査中です。
※追記 2/27
動作したバージョンをアップしました。

基本的なPOST送信の方法

コールアウトで外部にHTTP送信する場合、
ヘッダーやボディの中身を順番に設定していき、送信、となる。
(この基本的な内容がわかっていなくて苦労した)

POSTやGETで送信されるデータの基本的な内容は以下。
[Web] HTTPリクエストの中身を学んでみた。GETやPOSTの違いなど

送信内容例はこんな感じ。(上記サイト内から引用)

POST /www.hoge.com/test.php HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Type: text/plain
Content-Length: 23

key1=value1&key2=value2

apexからの基本的なPOST送信の方法は以下。
[Salesforce][Force.com]外部サイトにHTTPアクセス(Callout)する
(上記サイトから引用、編集)

HttpRequest request = new HttpRequest();
request.setEndpoint('http://****アクセスしたいAPIのURLだよ!****');
request.setMethod('POSTとかGETとか!');
request.setHeader('Accept','text/plain, */*');
request.setHeader('Accept-Charset','Shift_JIS,utf-8;q=0.7,*;q=0.3');
request.setHeader('Accept-Encoding','gzip,deflate,sdch');
request.setHeader('Accept-Language','ja,en-US;q=0.8,en;q=0.6');
request.setHeader('Connection','keep-alive');
request.setHeader('Content-Type','text/xml; charset=UTF-8 ');
String prams = 'key1=value1&key2=value2';
request.setBody(prams);

Http http = new Http();
HttpResponse response = http.send(request);
String responseBody = response..getBody();

最初に上げた送信内容のボディ部分に、getパラメータのようにつなげて書かれている。
なので、そのようにボディ部分に書いてやればいい。
[Apex]WebコールアウトでPOST送信する場合のパラメータの設定方法は?

注意点としては、コールアウトするURLは事前にドメインを指定しておく必要があるよう。
指定してないと、Unauthorized endpoint, please check Setup->Security->Remote site settings.とエラーが出る。

設定 -> セキュリティのコントロール -> リモートサイトの設定

さらに、接続するURLはSSLでないとエラーが返されてしまう。
The requested URL could not be retrieved

ちなみに、配列で送信する場合は以下。

params = 'hoge[]=huga&hoge[]=fuge';
request.setBody(params);

POSTでファイルを送信する

参考:Post ‘multipart/form-data’ out of Salesforce.com with APEX
スペイン語なので読めないけど、コード部分は読める。

そのまま送信すると、送信先のPHP側で、$_FILESにデータが入っていた。

この方法で、ファイルと一緒にパラメータも送信するには、
POST送信する際のボディ内容を再現すればいいよう。

いまさら聞けないHTTPマルチパートフォームデータ送信
(上記内容から引用)

POST test.php HTTP/1.1\r\n
Host: satoxpochi.com\r\n
Content-Type: multipart/form-data; boundary=---------------------------102852708831426\r\n
Content-Length: 「ボディ部のサイズ」\r\n
\r\n
-----------------------------102852708831426\r\n
Content-Disposition: form-data; name="password"\r\n
\r\n
ponpoko\r\n
-----------------------------102852708831426\r\n
Content-Disposition: form-data; name="level"\r\n
\r\n
high\r\n
-----------------------------102852708831426\r\n
Content-Disposition: form-data; name="filename"; filename="text.txt"\r\n
Content-Type: application/octet-stream\r\n
Content-Transfer-Encoding: binary\r\n
\r\n
abcd
-----------------------------102852708831426--\r\n

このように、送りたい情報分だけ区切り線でつないでいけばいい。
(1つのパラメータで区切り1つ分!)

また、visualforceのinputでfileを送信するには以下のようにする。

[apexクラス]
public String FileName { get; set; }
public Blob FileBody { get; set; }

[visualforceページ]
<apex:inputFile value="{!FileBody}" filename="{!FileName}"/>

これで、FileNameにファイル名、FileBodyにファイルが入る。

これらを踏まえて、最終的な送信部分のソースは以下。
POSTでデータとファイルをコールアウトで送信する。

[Visualforceページ]

メールアドレス1:<apex:input value="{!Email1}" /><br />
メールアドレス2:<apex:input value="{!Email2}" /><br />
<br />
添付ファイル : <apex:inputFile value="{!FileBody}" filename="{!FileName}"/>

[apexクラス]

HttpRequest request = new HttpRequest();
request.setEndpoint('https://送信先アドレス.php');
request.setMethod('POST');
request.setHeader('Accept-Language', 'ja');

String boundary = String.valueOf(DateTime.now().getTime());
String body = '';
body+='------------' + boundary + '\r\n';
body+='Content-Disposition: form-data; name="to[]"\r\n';
body+='\r\n';
body+=Email1 + '\r\n';
body+='------------' + boundary + '\r\n';
body+='Content-Disposition: form-data; name="to[]"\r\n';
body+='\r\n';
body+=Email2 + '\r\n';
body+='------------' + boundary + '\r\n';
body+='Content-Disposition: form-data; name="data"; filename="' + FileName + '"\r\n';
body+='Content-Transfer-Encoding: base64\r\n';
String contentType = 'application/octet-stream';
body+='Content-Type: ' + contentType + '\r\n\r\n';
body+=EncodingUtil.base64Encode(FileBody);
body+='\r\n------------' + boundary + '--';
request.setHeader('Content-Type', 'multipart/form-data; boundary=----------' + boundary);
request.setHeader('Content-Length',String.valueof(body.length()));
request.setBody(body);

Http http = new Http();
HttpResponse response = http.send(request);
ResResult = response.getBody();

送信先のPHPでの受信内容は以下。

($_POST)
array(1) { 
    ["to"]=> array(2) { 
        [0]=> string(14) "mail1@hoge.com" 
        [1]=> string(14) "mail2@huga.com"
    }
}

($_FILES)
array(1) { 
    ["data"]=> array(5) { 
        ["name"]=> string(8) "test.txt" 
        ["type"]=> string(24) "application/octet-stream" 
        ["tmp_name"]=> string(14) "/tmp/phpcEwVr6" 
        ["error"]=> int(0) 
        ["size"]=> int(309276) 
    }
}
   このエントリーをはてなブックマークに追加