LoginSignup
81
80

More than 5 years have passed since last update.

AngularJSでのHTTPrequest(主にPOST)にはまった件 #ng_jp

Last updated at Posted at 2014-12-01

@can_i_do_webさんに指名(?)を頂いたといことで。
AngularJS Advent Calendar 2014 (adventarの方) の1日目の記事です! 先陣を切らせて頂きます。

はじめに

今回はAngularJSでHTTPrequestをするときにかなりハマった話(笑)をまとめたいと思います。

同じようにハマる人がいるかもしれないのでメモしておきます。

私のスペックは

  • バックエンドのエンジニア
  • Angular.JSは趣味に近い形で勉強中
  • Angular.jsは雰囲気で書いていて理解はまだ追いついてない

という感じなので、初学者の人は同じエラーに出会うかもしれません

Access-Control-Allow-Origin.

 今日はこのあたりでめちゃハマってました。 APIのレスポンスを返す側がクロスドメイン環境を許可していない場合にクライアント側で表示されるエラーっていう認識です。

こんな感じのエラーが出ます。

XMLHttpRequest cannot load http://localhost:1337/. Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin.
Failed to load resource: Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin. 

基本的にサーバー側で解決

続 クロスドメインで使う XMLHttpRequest と CORS の話にもあるようにサーバー側で全てのオリジンを許可する必要があります。

例えばPHPでAPIを作ってる場合は

hoge.php
header('Access-Control-Allow-Origin: *');

とすればクロスドメイン環境でも問題無くアクセス出来ます。

クライアント側でのヘッダー問題もあった

今回は、クロスドメイン環境では分かるんですけど、同じドメイン化でも同様のエラーが発生しました。

いつもはjQueryで$.ajaxを使っていたのですが、AngularJSの場合は$http$resourceを使ってHTTP通信をします。この時の設定をしないとエラーが発生するようでした。

AngularJSでのhttp通信はCodeGridの記事が分かり易いです。
(https://app.codegrid.net/entry/angularjs-6)

後述するその辺の設定を(おそらく)jQueryだとデフォルトでやってくれていたんですね。

今回の構成

基本的にAPI設計になっています。
* サーバー側: Rails 4.2
* フロント側: AngularJS 1.3

生じてた問題

1. POSTしたつもりがmethodがOPTIONSになっていた

jQueryの$.ajaxと同じ形で単純にPOSTしているつもりだったのですが、

Access-Control-Allow-Originのエラーがコンソールに表示され、

サーガー側のログを見ると、methodがOPTIONSになっていると言われました。

API設計での開発でのジレンマと、フロントエンジニアのサーバー側を実装についてで書いたNode.jsサーバーで localhostに向けてHTTPリクエストをしてもAccess-Control-Allow-Origin. が発生していました。

サーバー側で受けとったデータを見ると

method: OPTIONS
post: {} object

といった

解決策: configの$httpProvierでHeaderを設定する

$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;application/json;charset=utf-8';

これを設定することでAccess-Control-Allow-Originエラーは出なくなります。

application/x-www-form-urlencoded をヘッダーに設定してURLエンコードした形でデータを渡す必要があったみたいです。

2. POSTデータのKey,Valueがおかしい

1の問題が解決されるとmethodはPOSTで送信されていました。
ただ、以下のような形でリクエストされていて、想定のリクエストと比べると ですよね。

method: POST
post: { '{"user":{"email":"garden1122@karumai.com","password":"karumaimai","password_confirmation":"karumaimai"}}': '' } object

オブジェクトのキー名にPOSTリクエストのデータがurlエンコードされて全て文字列で入っちゃってる感じでした。

Rails側のログはこんな感じです

解決策: $.param() を使う

色々探しまわってたら、Stack Over Flowで見つけました。
How can I post data as form data instead of a request payload?

データを送信するときに$.param()でパースして送信してあげると上手くいくみたいでした。

  • $httpの場合
var req = {
    method: 'POST',
    url: 'http://localhost:1337/',
    data: $.param({fkey: "key"})
}

$http(req).success(function(){}).error(function(){});
  • $resourceの場合
UserModel.email = "aaa";
UserModel.save($.param({key: 'key'}), function(data){
    console.log('seikou:',data);
});

こうすることで元々想定していた正しい形でHTTPリクエストを送ることができました :)

post: { 'user[email]': 'garden1122@karumai.com',
  'user[password]': 'karumaimai',
  'user[password_confirmation]': 'karumaimai' } object

ここまで来るのに大分掛かりました汗

まとめと学んだこと

今までAccess-Control-Allow-Originはサーバー側の設定で回避出来ると思っていたのですが、フロント側でもヘッダーの設定など設定を変えないと行けない部分があることを学びました。

まとめ

API設計での開発でのジレンマと、フロントエンジニアのサーバー側を実装についてでも書いたのですが、API設計でのAPI結合テストではAccess-Control-Allow-Origin.に限らず問題発生があるかもしれないので HTTP Header の知識は必要ですね。

ここでかなり詰まってしまったのでこれから爆速で追い返します。

81
80
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
81
80