🍖

フロントコントローラーのルーティング問題を解決したい

2024/06/11に公開2

悩み

CraftCMSを始めとしてLaravelやsymfonyなどのフレームワークにもある
URLのリライト設定でどうしたらいいか分からないこの問題。
基本的にドキュメントルートにはリクエストを集約するためのindex.php
それを制御する.htaccessがあるが、
以下のような構造の場合、ちょっとした問題が発生する。

┣ craft/
┃  ┣ その他のディレクトリ/
┃  ┗ templates/
┃    ┣ index.twig
┃    ┗ about/
┃      ┗ index.twig
┗ htdocs/
  ┣ cpresources/
  ┣ index.php
  ┣ .htaccess
  ┣ assets/
  ┗ about/   ← こいつ
    ┗ assets/
      ┣ js/
      ┣ css/
      ┗ images/

コーディングガイドラインで「下層のassetsはパスを揃えて配置する」パターンである。
CraftCMSの場合、静的ページからhtmlを分離してtemplatesに組み込むという作業フローになるのだが
フロントコントローラの制御によってエラーになってしまうのである。

CraftCMSのデフォルトのhtaccess

.htaccess
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Send would-be 404 requests to Craft
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
    RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>

発生する問題

この時https://shindev.com/about/へアクセスした場合、
ドキュメントルート配下にassets類を置くためのaboutディレクトリが存在しているため
RewriteCond %{REQUEST_FILENAME} !-dの条件を満たさずフレームワークを素通りしてしまい、
craft/templates/about/index.twigが読み込まれない(403エラー)のである。
(要するにhtdocs/about/を参照する流れになる)

ブラウザで描画される/about/(index.html)内に書かれるassets類のパスの指定は

<script src="/about/assets/js/index.min.js"></script><link rel="stylesheet" href="/about/assets/css/index.css" />

みたいな形で記述されているため、assetsはドキュメントルート配下に設置しなければならないのだが。

みんなどうしてるんだろう

stack exchangeでも聞いてみたけどうまく伝わってなさそう。。。

https://craftcms.stackexchange.com/questions/41783/references-to-static-assets-placed-under-subfolders

これ結構ありそうな問題だと思うんだけどな〜

https://qiita.com/tkek321/items/a43c83ea911099c23f6f

不健康そうな解決策

.htaccess
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Send would-be 404 requests to Craft
    RewriteCond %{REQUEST_FILENAME} !-f
#  ↓コメントアウト
#    RewriteCond %{REQUEST_FILENAME} !-d
# ↑コメントアウト
    RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
    RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>

これはQiitaの人も言ってるけど何が起きるか分からないのでやらない方がいいかもしれない。

健康そうな解決策

.htaccess
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Send would-be 404 requests to Craft
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d [NC,OR] # ←add
#↓add
    RewriteCond %{REQUEST_URI} (.+)/$
#↑add
    RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
    RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>

こちらを参考に
https://qiita.com/kawaz/items/d3a7adc1445113141f3b

リクエストがfでない&dでない
または
URIが/の場合〜
という設定にしたところ大丈夫な感じになった。

例外が思いつかないので一旦これで様子を見てみようと思う。

おわり。

Discussion

mersymersy

考えたことなかったですが、確かにこれはどうやるのがいいんでしょうね。。

shin_devshin_dev

割とありそうなパターンかと思うんですが意外にナレッジが少ないのですよねぇ...
↓こことかでもやっぱりRewriteCond %{REQUEST_FILENAME} !-dをコメントアウトしましょうという結論で〆られてました。。
https://stackoverflow.com/questions/24579107/laravel-homestead-403-forbidden-on-nginx

原則/craft/templates/xxxxx/と名前が被ったらダメなことは理解しつつも、今回のような場合どうするのがベターか対策は持っておきたいところです...。