まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:http

StrongLoopLoopBack を使うと、データベースのモデルを定義するだけで CRUD の REST API を生成し、OpenAPI(Swagger) スタイルのドキュメントと併せて簡単に公開できます。この辺りについては以前のブログエントリを参照してください:
CentOS に StrongLoop をインストールする


ところで、LoopBack を使って公開された API にはパラメータで挙動を指定できるものもあります。例えばモデルの一覧を取得する GET リクエストでは一覧を絞り込むためのクエリーを指定したり、取得結果の数やオフセットを指定することも可能です:
2016020601


そのための方法を紹介します。例えば items というテーブルに対して LoopBack で CRUD の API を作成したと仮定します。items の一覧を取得するには以下の様な URL に対する HTTP リクエストを GET で実行することになります(XX.XX.XX.XX は LoopBack が動いているサーバー):
http://XX.XX.XX.XX/api/items/

さて、一覧の検索条件(例えば id < 100)を指定する場合、SQL ではこのように指定することになります:
> select * from items where id < 100;

この条件を指定して上記の HTTP GET リクエストを実行するには、つまり id < 100 のものだけの一覧を API で取得するには、以下の様なパラメータを指定して実行します:
http://XX.XX.XX.XX/api/items?filter[where][id][lt]=100

filter という名前に [where] 句が指定され、更に条件である [id] が [lt] (Less Than) で 100 である、という条件が指定されていることになります。


一方、一覧の検索結果の取得数(例えば10件)を指定する場合、SQL(MySQL) ではこのように指定します:
> select * from items limit 10;

この条件を指定して HTTP GET リクエストを実行するには、以下の様なパラメータを指定して実行します:
http://XX.XX.XX.XX/api/items?filter[limit]=10

filter という名前に [limit] 句が指定され、その値が 10 である、という条件が指定されていることになります。なんとなくコツが分かってきましたか?

ちなみに一覧の検索結果の取得数を 50 件目からの 10 件、とするには SQL(MySQL) ではこのように指定します:
> select * from items limit 50, 10;

limit 句を指定し、オフセットが 0 以外の場合は limit 数の前にオフセット数を指定します。これを API のパラメータで指定するには以下のようにします:
http://XX.XX.XX.XX/api/items?filter[limit]=10&filter[offset]=50

クエリーや結果取得の条件は同時に指定することができます。例えば「 id < 100 のものをオフセット 50 で10 件取得」するのであれば、API ではこのように指定します:
http://XX.XX.XX.XX/api/items?filter[where][id][lt]=100&filter[limit]=10&filter[offset]=50

filter の使い方、なんとなくコツがわかってきましたか? 使っているデータベースの種類は何で、そのデータベースでは SQL ではどういった指定になるか、をイメージできるとわかりやすいです。


このパラメータに関する API ドキュメントはこちら:
https://docs.strongloop.com/display/public/LB/Where+filter
 

ウェブサーバー(HTTP サーバー)を使う場合、なんらかのアクセスログを残すことになります。例えば Apache HTTPD の場合、デフォルトでアクセスログは /var/log/httpd/access_log に残ります。そのフォーマットは /etc/httpd/conf/httpd.conf 内で設定/カスタマイズできます。
2015012200


デフォルトの httpd.conf では、以下の様なログフォーマットが指定されています:
LogFormat "%h %l %u %t \"%r\" %>s %b common

暗号のような記述ですが、左から順にこのような意味があります:
 %h : 接続元のリモートホスト名(IPアドレス)
 %l : クライアント識別子(取得できない場合は - )
 %u : 認証時のユーザー名(取得できない場合は - )
 %t : 時刻
 %r : リクエストの最初の行の値
 %s : レスポンスステータス
 %b : 送信バイト数(0バイトの場合は - )

このログフォーマットであれば、以下の様なログが取得できることになります:
192.168.1.101 - - [20/Jan/2015:11:32:29 +0900] "GET / HTTP/1.1" 200 -


最初の値がアクセス元のホストになります。つまりこれで(プロクシが使われている場合はプロクシのアドレスになりますが)どこからのアクセスがあったのか、という情報が分かります。


ところが、このアクセス元ホストが分からなくなる場合があります。それは HTTP サーバーがロードバランサ経由で使われていた場合です。サーバーの負荷軽減などの目的で、サーバーを複数台構成にしてロードバランサ経由で利用する、というケースは珍しくないと思います(クラウド環境によっては1台構成でもロードバランサ経由になることもあります)。ただその場合、この設定だとアクセス元ホストは必ずロードバランサの IP アドレスになってしまい、結果として常に同じホストからのアクセスがあったとログに記録されることになります。

これを避けるには httpd.conf をカスタマイズする必要があります。具体的にはこんな感じに:
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b common


%h の代わりに %{X-Forwarded-For}i という記述に変えました。この意味ですが、まず %{XXX}i という記述は「リクエストヘッダに含まれるヘッダー名 XXX の値」です。つまりこの記述は「リクエストヘッダに含まれる X-Forwarded-For ヘッダの値」をログに書き出すよう指示していることになります。

そしてリクエストヘッダの X-Forwarded-For ですが、これはプロクシやロードバランサなどのキャッシングサーバーに接続するクライアントの送信元 IP アドレスです。つまりキャッシングサーバーから見た時の %h の値がこのヘッダ値に入ってくるので、その値を取り出してログに記録すればよい、ということになるわけです。 そこで上記のような設定をすることでロードバランサ経由であっても、元のクライアントの IP アドレスを記録できるようになるのでした。

なお、この方法は HTTP プロトコルに限って有効です。HTTPS では暗号化によって HTTP ヘッダに送信元 IP アドレスが記録できるかどうか、ロードバランサによって変わってきてしまいます。お使いのロードバランサが HTTPS をサポートしているか、サポートしていない場合の対応方法などはお使いのクラウド業者に問い合わせる必要があると思っています。



 

PHP を使ったアプリケーション開発フレームワークの1つ、cakePHP を最近あちこちで使うようになったので、その環境を構築する手順を紹介します。


まず前提条件として、PHP/MySQL(または mongoDB、或いは両方)/Apache HTTPD がセットアップ済みである必要があります。これらは全て異なるサーバーに用意しても構いませんが、本エントリでは同一のマシン内(localhost)に構築する前提で紹介します。

HTTP サーバーとして Apache HTTPD の代わりに Nginx を使うこともできますが、少し手順が異なってくるのでここでは詳細は省略します。DB は RDB を使うのであれば MySQL(又は互換性のある MariaDB) を、高速な JSON DB を使うのであれば mongoDB を、併用するのであれば両方をセットアップしておきます。これら前提条件の導入手順の詳細は以下を参照してください:
CentOS に PHP を導入する
CentOS に MySQL をインストールする
mongoDB を CentOS 上にインストールする
CentOS に Apache HTTPD を導入して SSL を有効にする


前提条件の用意が済んだら、公式ページから最新版の cakePHP をダウンロードします。仮にダウンロードモジュール名が cakephp-2.4.7.zip(バージョン 2.4.7)であったと仮定して以下の説明を続けます:


まずは cakePHP で開発するアプリケーションが使うデータベースを定義します。既存のものを使っても構いませんし、新規に作成しても構いません。ここでは MySQL 内に "cakedb" という名前の UTF8 データベースを作成しています。また同データベースにアクセスするためのユーザー cake_user を定義しました:
# mysql -u root -p
Enter password: (パスワード入力)
  :
  :
mysql> create database cakedb default character set utf8;
Query OK, 1 row affected (0.00 sec)
mysql> grant all privileges on cakedb.*  to cake_user@localhost identified by 'cake_pass' with grant option;
Query OK, 1 row affected (0.00 sec)
mysql> quit
#

次に cakePHP モジュールを展開します。この例ではドキュメントルート(/var/www/html/)以下に展開して、cake/ というフォルダ名に変更しています:
# cd /var/www/html
# unzip /tmp/cakephp-2.4.7.zip
# mv cakephp-2.4.7 cake

これで cakePHP がドキュメントルート以下に展開されました。が、利用するにはもう少し設定が必要です。まずは接続先データベースを定義します。まず app/Config/database.php.default を app/Config/database.php にコピーして、その内容を以下のように変更/保存します(この内容はデータベースに MySQL を使う前提で記載しています):
public $default = array(
  'datasource' => 'Database/Mysql',
  'persistent' => false,
  'host' => 'localhost',
  'login' => 'cake_user',
  'password' => 'cake_pass',
  'database' => 'cakedb',
  'prefix' => '',
  'encoding' => 'utf8'
);

public $cakedb = array(
  'datasource' => 'Database/Mysql',
  'persistent' => false,
  'host' => 'localhost',
  'login' => 'cake_user',
  'password' => 'cake_pass',
  'database' => 'cakedb',
  'prefix' => '',
  'encoding' => 'utf8'
);
この設定では上記で作成した MySQL 内の cakedb データベースに cake_user : cake_pass で接続するための $default という配列変数を定義しています。また全く同じ内容を $cakedb 変数にも設定しています。

cakePHP では特に何の指定もしない場合の接続先は $default 変数に定義する必要があります。そのための設定です。

なお、それだけならばわざわざ $cakedb 変数を定義する必要はないのですが、後から $default 以外の接続先を利用することも考慮してこのような設定にしています。MySQL 内の別のデータベースや、MySQL 以外の別データベースにも接続したり、接続先を随時変更したりすることができるようにこのようにしている(逆を言えば、MySQL 内の1つのデータベースだけを対象に読み書きするのであれば $default だけの定義で充分)、と理解してください。


次に cakePHP は一時的にファイルを作成することがあるため、そのための書き込み権限を付与します:
# cd app
# chmod -R 777 tmp

最後にセキュリティのための設定を行います。app/Config/core.php 内に 'Security.salt'(ハッシュキーの生成に用いる文字列)、および 'Security.cipherSeed'(暗号化・復号化で利用する文字列)がデフォルト状態で定義されています。これをそのまま使うのは危ないので、独自の内容に変更します。前者は半角英数字、後者は数値文字列で適当な内容に変更して保存ます:
    :
  Configure::write('Security.salt', 'ABCDabcd1234' );
    :
    :
  Configure::write('Security.cipherSeed', '12345678' );
    :


この時点で cakePHP を利用することができるようになります。ブラウザでドキュメントルートの cake サブディレクトリにアクセスすると、以下の様な画面になるはずです:
2014051301


この画面では緑および黄色のメッセージしか出ていませんが、ここに赤いメッセージが出ている場合はまだ設定が正しく完了していないことを意味しています。メッセージ内容を見直して、適宜対応してください。

とりあえず最低限のインストールはこんな感じです。



 

WordPress.com でも使われていて、Apache HTTPD, IIS に次ぐシェアを持つ HTTPD サーバー、それが Nginx(「エンジンエックス」)です。リバースプロキシとしての機能も併せ持ち、並行処理性能と省メモリ性能を重視して開発が続けられているオープンソースサーバーです。

この Nginx を CentOS にインストールする手順を紹介します。

インストール方法はソースからビルドする方法もありますが、簡単なのは yum リポジトリを作ってダウンロード&インストールが楽だと思います。

というわけで、まずは yum リポジトリを作成します:
# rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm

これで /etc/yum.repos.d/nginx.repo が作成されて準備完了。あとは yum でインストールです:
# yum install nginx

インストール自体はこれだけです(ちなみにデフォルト状態でのドキュメントルートは /usr/share/nginx/html/ です)。 この段階で一度動作確認してみます。まずはサーバーを起動:
# /etc/init.d/nginx start

そしてウェブブラウザでサーバーにアクセスします。"Welcome to nginx" と表示されれば Nginx のインストールは成功しています:
2014021301


Nginx のインストールはこれだけでもできていますが、実際には PHP などと合わせたアプリケーションサーバーとして使いたいですよね。そのための追加設定も紹介しておきます。

Nginx で PHP を使うためのインターフェースにはいくつか選択肢がありますが、今回は PHP-FPM を使う方法を紹介します。まずは yum で php-fpm をインストールします:
# yum install php-fpm

PHP-FPM はデフォルトでは Apache HTTPD 用の設定になっています。これを nginx ユーザー/ nginx グループで動作するように設定ファイルを変更します:
# vi /etc/php-fpm.d/www.conf

  :
user = nginx   # user = apache から変更
  :
group = nginx   # group = apache から変更
  :

最後に nginx の設定を変更して、ドキュメントルート上で PHP(-FPM) が動作するようにします。記述箇所はファイルの下の方にはじめから記載されているのでコメントアウトしてドキュメントルートディレクトリを指定するのが簡単だと思います:
# vi /etc/nginx/conf.d/default.conf

  :
location ~ \.php$ {
#    root           html;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /usr/share/nginx/html$fastcgi_script_name;
    include        fastcgi_params;
}
  :

この後に php-fpm を起動してから、nginx を再起動します:
# /etc/init.d/php-fpm start
# /etc/init.d/nginx restart

動作確認用に、ドキュメントルートに PHP 情報を出力するスクリプトファイル(phpinfo.php)を用意します:
# echo '<?php phpinfo(); ?>' > /usr/share/nginx/html/phpinfo.php

この状態でこのファイルにウェブブラウザからアクセスして、以下の様な PHP 情報が出力されれば成功です:
2014021302


これで Nginx を導入し、PHP 連携までが可能になりました!

 

このページのトップヘ