Удаление index.html и.html из URL с помощью nginx

Моя основная цель - предоставить nginx следующие чистые URL:

  • / служит /index.html
  • /abc/ служит /abc/index.html
  • /abc/def служит /abc/def.html
  • /abc перенаправляет на /abc/

Чтобы иметь канонические имена для каждого ресурса, я также хочу нормализовать любой URL с избыточными именами файлов или расширениями:

  • /index.html перенаправляет на /
  • /abc/index.html перенаправляет на /abc/
  • /abc/def.html перенаправляет на /abc/def

Директивы, которые, как я думал, могли бы сделать это:

index index.html;
try_files $uri.html $uri $uri/ =404;

# Redirect */index and */index.html to *.
rewrite ^(.*)/index(\.html)?$ $1 permanent;
# Redirect *.html to *.
rewrite ^(.+)\.html$          $1 permanent;

Тем не менее, результат этого отличается от того, что я ожидал:

  • /, /index а также /index.html все перенаправить на / (Цикл).
  • /abc а также /abc/ оба перенаправить на /abc/ (Цикл).

(Работает так, как /abc/def.html а также /abc/def; не работают только URL-адреса каталогов.)

Я не уверен, что здесь происходит; может быть, я неправильно понимаю, как rewrite работает?

(Я уже пытался использовать блоки местоположения вместо этого, но это также приводит к появлению петель try_files выполняет внутреннее перенаправление в блок местоположения, который отправляет HTTP 301.)

Редактировать: По сути, мне нужно что-то вроде блока местоположения, который соответствует только исходному URI запроса, но игнорируется для внутренних перенаправлений, поэтому он не создает цикл в сочетании с директивой try_files.

2 ответа

Возможно, вы ищете решение, подобное тому, которое описано здесь:

server {
    listen       80;
    server_name  mysite.com;

    index index.html;
    root /var/www/mysite/public;

    location / { 
        try_files $uri $uri/ @htmlext;
    }   

    location ~ \.html$ {
        try_files $uri =404;
    }   

    location @htmlext {
        rewrite ^(.*)$ $1.html last;
    }   
}

Я полагаю, что нашел решение, хотя у меня недостаточно опыта, чтобы сказать, может ли оно сломаться в особых случаях или может быть легче решено другим способом.

По сути, проблема в том, что location ~ ... {} блок сопоставляется не только с исходным URI запроса, но и с результатом try_files и другие переписывает. Так что, если у меня есть блок местоположения для удаления index.html или.html с перенаправлением, то он будет работать не только при запросе клиента index.html или же abc.html напрямую, но также, если клиент запрашивает / или же abc и сервер внутренне перенаправляет их в /index.html а также abc.html соответственно, вызывая цикл перенаправления.

Тем не менее, модуль перенаправления обеспечивает if директива, которая может проверить $request_uri переменная - это остается неизменным внутренними перенаправлениями:

index index.html;
try_files $uri $uri.html $uri/ =404;

# like "location ~", but only for matching the original request. 
if ($request_uri ~ /index(.html)?$) {
  rewrite ^(.*/)index(.html)?$ $1 permanent;
}
if ($request_uri ~ \.html$) {
  rewrite ^(.*)\.html$ $1 permanent;
}

(Обратите внимание, что все эти директивы теперь существуют в контексте сервера, без каких-либо блоков местоположения.)

Другие вопросы по тегам