+ Start a Discussion
ms-hase-q23eems-hase-q23ee 

HttpRequestを使用したRESTログインに失敗する

お世話になっております。HttpReuestクラスを使用して、RESTサービスへのログインを行っているのでスが、失敗します。マニュアルを調べてみても手がかりになりそうな記述がありません。次のコードの何が悪いのか、わかる方は居ますでしょうか?


private class xxxManagerTest {

    static {
        RestLogin();
    }


    static testMethod void testHandleGetRequest() {
        RestRequest req = new RestRequest();
        RestResponse res = new RestResponse();

        req.requestURI = 'https://ap.salesforce.com//services/apexrest/xxxManager/?call=step';
        req.httpMethod = 'GET';

        RestContext.request = req;
        RestContext.response = res;

        String s = xxxManager.handleGetRequest();
        System.assertEquals('', s);
    }

    static  void RestLogin() {
        Http http = new Http();
        String parameter = '';
        HttpRequest request = new HttpRequest();
         HTTPResponse response = new HTTPResponse();
           
//        request.setHeader('Accept','application/json');
//        request.setHeader('Accept-Language','ja');
        request.setHeader('content-type','application/x-www-form-urlencoded');

        parameter = 'grant_type=password';
        parameter+= '&client_id='+EncodingUtil.UrlEncode('3MVG9I1kFE5Iul2A69UT5J2zvjXBFdICh5Q_ytVdxBPocfseEZHA1Z6aA1EEWI5b0VVqPiSyB8z74Muf4sueU','UTF-8');
        parameter+= '&client_secret='+EncodingUtil.UrlEncode('8201551502817029738','UTF-8');
        parameter+= '&username='+EncodingUtil.UrlEncode('aaaa@bbb.co.jp.sb1','UTF-8');
        parameter+= '&password='+EncodingUtil.UrlEncode('passwd','UTF-8');

        String endpoint = 'https://test.salesforce.com/services/oauth2/token';
        request.setEndpoint(endpoint);
        request.setMethod('POST');
        request.setBody(parameter);
        try {
            response = http.send(request);
        } catch(Exception e ) {
            system.debug(e.getMessage()) ;
            system.debug(request.getBody());
            system.debug(request.getBodyDocument());
            
            system.debug(http.toString());
        }
        system.debug('@@@@@@@@@@@@@@@@@ '+ JSON.deserializeUntyped(response.getBody()));
    }
}

client_idやclient_secretの設定が上手くいっている事は、curlコマンドやjavaのプログラムから確認できています。apexから呼ぶと上手くいきません。
必ず例外が発生して、以下のようなコードが表示されます。


デバッグログ:
:
:

23:43:55.202 (7202373668)|SYSTEM_METHOD_ENTRY|[65]|System.Http.send(ANY)
23:43:55.203 (7203532591)|EXCEPTION_THROWN|[65]|System.TypeException: TestMethod  ̄チᄄ ̄チラ ̄チᆭ¥ᆴレ￧ᄒᄅ ̄チユ ̄ツフ ̄チ゚ ̄テᄀ ̄ツᄑ ̄テテ ̄テノ ̄チᆵ ̄タチWeb  ̄ツᄉ ̄テᄐ ̄テモ ̄ツᄍ ̄ツᄈ ̄テᄐ ̄テᆱ ̄ツᄁ ̄ツᆭ ̄テネ ̄ツメ ̄ツᄉ ̄テン ̄テᄐ ̄テネ ̄チラ ̄チᆰ ̄チト ̄チ゚ ̄ツチ ̄タチ ̄テニ ̄ツᄍ ̄テネ ̄チᆵ ̄ツᄍ ̄ツᆳ ̄テテ ̄テラ ̄チユ ̄ツフ ̄チᄒ ̄チル ̄タツ
23:43:55.203 (7203587004)|SYSTEM_METHOD_EXIT|[65]|System.Http.send(ANY)



response = http.send(request);がエラーなのですが、そこで何が起きているのか、全く分かりません。
文字化けのようなものは何を意味するのか・・・


catchした部分でのsystem.debug()の結果は以下のとおりです。


TestMethod  ̄チᄄ ̄チラ ̄チᆭ¥ᆴレ￧ᄒᄅ ̄チユ ̄ツフ ̄チ゚ ̄テᄀ ̄ツᄑ ̄テテ ̄テノ ̄チᆵ ̄タチWeb  ̄ツᄉ ̄テᄐ ̄テモ ̄ツᄍ ̄ツᄈ ̄テᄐ ̄テᆱ ̄ツᄁ ̄ツᆭ ̄テネ ̄ツメ ̄ツᄉ ̄テン ̄テᄐ ̄テネ ̄チラ ̄チᆰ ̄チト ̄チ゚ ̄ツチ ̄タチ ̄テニ ̄ツᄍ ̄テネ ̄チᆵ ̄ツᄍ ̄ツᆳ ̄テテ ̄テラ ̄チユ ̄ツフ ̄チᄒ ̄チル ̄タツ

grant_type=password&client_id=3MVG9I1kFE5Iul2A69UT5J2zvjXBFdICh5Q_ytVdxBPocfseEZHA1Z6aA1EEWI5b0VVqPiSyB8z74Muf4sueU&client_secret=8201551502817029738&username=aaaa%40bbb.co.jp.sb1&password=passwd

null

System.Http[]



そもそもHTTPRequestクラスは情報が少なく、どのようにしてフォームパラメータを渡せば良いのか、またその結果をどのようにして確認すれば良いのか分かりません。このプログラムでもmethod=POSTを使っているのにGETの様なパラメータを作成しているので、果たしてこれでいいのかも判断がつきません。


ご存知の方は、教えてください。
宜しくお願いいたします。
Best Answer chosen by ms-hase-q23ee
Shingo YamazakiShingo Yamazaki
ms-hase-q23eeさん

こんにちは。
山﨑と申します。

今回のエラーはテストメソッドで発生しているようですが、HttpRequestを使用したクラスのテストには専用のモッククラスを利用しないといけません。
このあたりは公式のドキュメントと、日本語でわかりやすく解説されている記事がありましたので参考にしていただければ。

(公式・英語)https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_testing_httpcalloutmock.htm
(日本語による紹介記事)http://tyoshikawa1106.hatenablog.com/entry/2013/09/08/213715

また、実際にHttpRequestクラスで接続する際は、事前に接続先のURLが「リモートサイトの設定」で許可されている必要があります。
http://www.kokyakukanri.info/salesforce/blog/2010/11/apex-web-apex-http.html
設定済みかもしれませんが、念のため。

本件の内容からは若干逸れますが、デバッグログは開発者コンソールで表示したものでしょうか?それとも Force.com IDE か何かで表示したものでしょうか?
文字化けが解決しないようでしたら、組織の言語設定を一時的に英語に設定するとメッセージも英語に変換され、内容がわかるかもしれません(未確認ですが)

All Answers

Shingo YamazakiShingo Yamazaki
ms-hase-q23eeさん

こんにちは。
山﨑と申します。

今回のエラーはテストメソッドで発生しているようですが、HttpRequestを使用したクラスのテストには専用のモッククラスを利用しないといけません。
このあたりは公式のドキュメントと、日本語でわかりやすく解説されている記事がありましたので参考にしていただければ。

(公式・英語)https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_http_testing_httpcalloutmock.htm
(日本語による紹介記事)http://tyoshikawa1106.hatenablog.com/entry/2013/09/08/213715

また、実際にHttpRequestクラスで接続する際は、事前に接続先のURLが「リモートサイトの設定」で許可されている必要があります。
http://www.kokyakukanri.info/salesforce/blog/2010/11/apex-web-apex-http.html
設定済みかもしれませんが、念のため。

本件の内容からは若干逸れますが、デバッグログは開発者コンソールで表示したものでしょうか?それとも Force.com IDE か何かで表示したものでしょうか?
文字化けが解決しないようでしたら、組織の言語設定を一時的に英語に設定するとメッセージも英語に変換され、内容がわかるかもしれません(未確認ですが)
This was selected as the best answer
ms-hase-q23eems-hase-q23ee
ご返信ありがとうございます。どちらも有力な手がかりになりそうです。このメッセージはforce.com IDEから出力したものです。進捗がありましたらご返信します。

ところでもう一つ、お伺いしたいのですが、「リモートサイトの設定」の設定はなぜ存在するのでしょうか?この機能はリリース後、モバイルからアクセスされ、色々な場所のwifiスポットからアクセスされる事になっています。当然、IPの特定なぞできるはずが無いので、全てを許可にしなければならないのですが、そうは出来ないように見えます。

現在、試験中なので、202.0.0.0-202.255.255.255 のようなパターンを設定しているのですが、これを256個作成しなければならないのでしょうか?

ご存知の方は教えてください。

宜しくお願いいたします。
Shingo YamazakiShingo Yamazaki
「リモートサイトの設定」は Salesforce から Salesforceの "外" にアクセスする際に
許可するアクセス先を指定するためのものです。

以下では例として、Apex から GitHub という外部Webサービスの API を叩いています。
http://dackdive.hateblo.jp/entry/2014/06/09/003741

HttpRequest は ms-hase-q23ee さんが実現したいことに沿ってますでしょうか?
仮に実装している機能がSalesforce内で(Salesforce1モバイルアプリなどから)実行されるもので、
かつ Salesforce 内の他の機能を呼び出したいだけでしたらHttpRequestは不要かと思います。

また、設定がなぜ存在するのかという質問の答えについては、おそらくセキュリティのためだと思います。
管理パッケージにするとコードの中身は参照できないので、外部のwebサービスにデータを流出するような処理が書かれていてもインストールしたユーザーにはわかりませんが
そのためにはリモートサイトの設定もパッケージに含める必要があるので、インストールするユーザーがURLを確認できます。