rewrite
и if
следует избегать с Nginx.Знаменитая строка: «Nginx - это не Apache»: другими словами, Nginx имеет лучшие способы обработки URL-адресов, чем переписывание.return
все еще технически является частью модуля перезаписи, но он не несет издержек rewrite
и не так подвержен предостережениям, как if
.
Nginx имеет всю страницу на почему if
является "злом" .Он также предоставляет конструктивную страницу, объясняющую , почему rewrite
и if
плохие , и как вы можете обойти это.Вот что говорит эта страница относительно rewrite
и if
:
Это неправильный, громоздкий и неэффективный способ.
Вы можете решить эту проблемуправильно используя return
:
server {
listen 443 ssl;
# You will need a wildcard certificate if you want to specify multiple
# hostnames here.
server_name domain.example www.domain.example;
# If you have a certificate that is shared among several servers, you
# can move these outside the `server` block.
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/cert.key;
# 301 indicates a permanent redirect. If your redirect is
# temporary, you can change it to 302 or omit the number
# altogether.
# $http_host is the hostname and, if applicable, port--unlike $host,
# which will break on non-standard ports
# $request_uri is the raw URI requested by the client, including any
# querystring
return 301 http://$http_host$request_uri;
}
Если вы ожидаете, что многие боты не отправляют заголовок Host
, вы можете использовать $host
вместо $http_host
, пока вы придерживаетесьпорты 80 и 443. В противном случае вам нужно будет динамически заполнить замену $http_host
.Этот код эффективен и безопасен, пока он появляется в корне server
(а не в блоке location
), несмотря на использование if
.Однако вам нужно будет использовать сервер по умолчанию, чтобы это было применимо, чего следует избегать с помощью https.
set $request_host $server_name:$server_port;
if ($http_host) {
set $request_host $http_host;
}
Если вы хотите использовать SSL / TLS для определенных путей, но запретите это в противном случае:
server {
listen 443 ssl;
server_name domain.example;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/cert.key;
location / {
return 301 http://$host$request_uri;
}
location /secure/ {
try_files $uri =404;
}
}
server {
listen 80;
server_name domain.example;
location / {
try_files $uri =404;
}
location /secure/ {
return 301 https://$http_host$request_uri;
}
}
Если ваш сервер не имеет прямой связи с клиентом - например, если вы используете CloudFlare - все становится немного сложнее.Вам нужно будет убедиться, что любой сервер, имеющий прямую связь с клиентом, добавляет в запрос соответствующий заголовок X-Forwarded-Proto
.
Использование этого беспорядочного предложения;полное объяснение см. IfIsEvil .Чтобы это было полезно, блок if
не может быть внутри блока location
по ряду сложных причин.Это заставляет использовать rewrite
для тестирования URI. Короче говоря, если вам нужно использовать это на рабочем сервере ... не надо.Подумайте об этом так: если вы переросли Apache, вы переросли это решение.
/ secure, / secure / и все, что находится в / secure /, обеспечит применение https, тогда как все другие URIбудет обеспечивать http.(?! )
PCRE-конструкция является отрицательным прогнозным утверждением .(?: )
является не захватывающей группой .
server {
# If you're using https between servers, you'll need to modify the listen
# block and ensure that proper ssl_* statements are either present or
# inherited.
listen 80;
server_name domain.example;
if ($http_x_forwarded_proto = https) {
rewrite ^(?!/secure)/ http://$http_host$request_uri? permanent;
}
if ($http_x_forwarded_proto != https) {
rewrite ^/secure(?:/|$) https://$http_host$request_uri? permanent;
}
}