4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Nginx で PC とスマートフォンでコンテンツをうまく出し分ける

Posted at

要件1

  • HTTP リクエストヘッダー User-Agent: により、スマートフォンか PC かを判別し、ドキュメントルートを切り替える。
    • PC 用ドキュメントルート = /var/www/public_html
    • スマートフォン用ドキュメントルート = /var/www/public_html/sp

よく見かける例

http {

  ...

  server {

    ...

    set $is_sp 0;
    if ($http_user_agent ~* "(iphone|ipod|android.*mobile)") {
      set $is_sp 1;
    }

    root /var/www/public_html;

    location / {
      if ($is_sp) {
        root /var/www/public_html/sp;
      }

    }
  }
}

間違いではない。でも...

同じことを、もう少しかっこよく

http {

  ...

  server {

    ...

    if ($http_user_agent ~* "(iphone|ipod|android.*mobile)") {
      set $path_prefix "/sp";
    }

    location / {
      root /var/www/public_html$path_prefix;
    }

  }
}

解説

root ディレクティブには変数が使える。ただそれだけのこと。

要件2

  • HTTP リクエストヘッダー User-Agent: により、スマートフォンか PC かを判別し、ドキュメントルートを切り替える。
    • PC 用ドキュメントルート = /pub/www/public_html
    • スマートフォン用ドキュメントルート = /pub/www/public_html/sp

ここまでは要件1と同じ。今回はそれに加えて、

  • スマートフォン用ドキュメントルートを優先してコンテンツを探す
    • スマートフォンで見たときに、スマートフォン用ドキュメントルートにファイルが存在すればそれを応答し、存在しなければ PC 用ドキュメントルートから探して見つかったらそれを応答する。

このように、スマートフォン用に最適化されたドキュメントが作られていたらそれを表示し、なければ PC 用コンテンツをそのまま表示したいというのは、コンテンツ制作現場では実践的でありがちな要件だと思う。

http {

  ...

  server {

    ...

    if ($http_user_agent ~* "(iphone|ipod|android.*mobile)") {
      set $path_prefix "/sp";
    }

    location / {
      root /var/www/public_html$path_prefix;
      try_files $uri $uri/ @pc;
    }

    location @pc {
      root /var/www/public_html;
    }

  }
}

解説

try_files ディレクティブで、コンテンツの探索順序を設定している。try_files $uri $uri/ までは普通で、その後ろに @pc という名前付きロケーションを設定している。
@pc ではドキュメントルートを PC 向けに設定しているので、「最初にスマートフォンのドキュメントルートを探し、なければ PC のドキュメントルートを探す」という、今回の要件を満たす動きになる。

ここで、こんな疑問が湧いてくるのではないだろうか。

Q1: PC で見たときは $path_prefix が未設定なので、PC 向けドキュメントルート /var/www/public_html を2回探すことになるんじゃないの?

そのとおりである。
たしかに無駄な処理かもしれない。しかし実際にはその無駄な処理にかかるオーバーヘッドは、たかがしれている。もしかすると Nginx 内部では動作が最適化されていて、無駄な処理自体行われていないかもしれない。(ソースを読んでいないのでわからないけど)

Q2: スマートフォンで見たときだけ /var/www/public_html/sp を探しに行けば良いのだから、if ブロックに try_files を書けば良いのでは?

try_files は if ブロックには書けない。http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files によると、try_files は server または location ブロックにしか書けないのである。

4
6
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
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?