share facebook facebook2 twitter menu hatena pocket slack

2014.11.14 FRI

Play Framework で X-Forwarded-for とかの HTTP リクエストヘッダを取得する

川原 洋平

WRITTEN BY川原 洋平

どうも、cloudpack の Play で Play しているかっぱ (@inokara) です。

はじめに

Play Framework を公開しようとする場合に素のアプリケーションサーバーでアクセスするか ELB 又は Nginx 等をリバースプロキシとして利用してアクセスすることが出来ると思います。

その際にアプリケーション側で接続元の IP アドレスや User Agent 等を取得したいよねってことで試してみました。

参考


やってみる

アプリケーションを作成

play new hoge

新しい hoge アプリケーションを作りましょう。

HTTP リクエストヘッダを覗くスクリプト

コントローラに HTTP リクエストヘッダを取得して JSON で出力するスクリプトを見よう見まねで下記のように書きました。

package controllers;
// JSON 扱う為に必要
import play.libs.Json;
import com.fasterxml.jackson.databind.node.*;
 com.fasterxml.jackson.databind.JsonNode;

import play.*;
import play.mvc.*;
// HTTP ヘッダを扱う為に必要
import play.mvc.Http.Request;

import views.html.*;

public class Application extends Controller {

  public static Result ip() {
    ObjectNode result = Json.newObject();
    Request req = play.mvc.Http.Context.current().request();
    String x = req.getHeader("X-Forwarded-For");
    String p = req.getHeader("X-Forwarded-Proto");
    String ua = request().getHeader("User-Agent");
    result.put("x-forwarded-for", x );
    result.put("x-forwarded-prot", p );
    result.put("user-agent", ua );
    return ok(result );
  }
}

JSON を扱う為には以下のような幾つかのライブラリをインポートする必要がありました。

また、今回やりたいことのキモとなる HTTP リクエストヘッダを扱う為には以下のライブラリをインポートする必要がありました。

とりあえず view は用意する必要無いので play run してしまいましょう。

play run

もしくは play して run でもよかばい。正常に起動したら curl なりブラウザでアクセスして確認してみます。

素でリクエストを投げる

リクエストは以下のように投げます。

client => Play

そして、以下のようなレスポンスを得ることが出来ます。

{
  "remote_address": "xxx.xxx.xxx.xxx",
  "user-agent": "curl/7.30.0",
  "x-forwarded-prot": null,
  "x-forwarded-for": null
}

“xxx.xxx.xxx.xxx” は接続元の IP アドレスとなります。

ELB 経由でアクセスしてみる

ELB を介したアクセスの場合…

client => ELB => Play

そして、以下のようなレスポンスが得られます。

{
  "remote_address": "172.31.14.xxx",
  "user-agent": "curl/7.30.0",
  "x-forwarded-prot": "http",
  "x-forwarded-for": "xxx.xxx.xxx.xxx"
}

“xxx.xxx.xxx.xxx” は接続元の IP アドレスとなります。また、remote_address には ELB の内部 IP が取得出来ています。

ELB => Nginx 経由でリクエストを投げる

さらに間に Nginx 等の Web サーバーを挟んだ場合…

client => ELB => Nginx => Play

以下のようなレスポンスが得られます。リバースプロキシは多段になっていますが、それぞれの IP アドレス(アクセス元を含む)がちゃんとリクエストヘッダ内に書かれていることを Play 側で認識しているようです。

{
  "user-agent": "curl/7.30.0",
  "x-forwarded-prot": "http",
  "x-forwarded-for": "xxx.xxx.xxx.xxx, 172.31.14.xxx"
}

ちなみに、Nginx の設定はこちらを参考にして以下の通り。

proxy_buffering    off;
proxy_set_header   X-Real-IP $remote_addr;
proxy_set_header   X-Scheme $scheme;
proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header   Host $http_host;
proxy_http_version 1.1;

upstream my-backend {
   server 127.0.0.1:9000;
}

server {
  listen       8080;
  server_name www.mysite.com;
  location / {
     proxy_pass http://my-backend;
  }
}

ということで…

なんだかんだで Play Framework で HTTP リクエストヘッダの取得方法について勉強することが出来ましたし、X-Forwarded-for とかの各種ヘッダ周りについての動作を確認することが出来ました。

おやすみなさい。

元記事はこちらです。
Play Framework で X-Forwarded-for とかの HTTP リクエストヘッダを取得する