larave/nginx постоянно возвращает 301 Moved Permanently

Разрабатываю приложение на laravel и vue. Локально всё работает прекрасно. Но когда загрузил приложение на сервер обнаружил что не работает ссылка из письма при подтверждении почты, а именно при переходе по ссылке из письма вечно происходит редирект и браузер выдаёт "Сайт выполнил переадресацию слишком много раз."

Ссылка из письма выглядит следующим образом -> http://mysite/email/verify/4/09VVTt2BKtjyUoXQoLamqOaZuauXSSvf?signature=5741aad143a4580fa785c6647c11923f1121e899d20cc770fb66a4e74e3933c4

Приложение делает переадресацию на http://mysite/auth/register/verify?next=http://mysite/email/verify/4/09VVTt2BKtjyUoXQoLamqOaZuauXSSvf?signature=5741aad143a4580fa785c6647c11923f1121e899d20cc770fb66a4e74e3933c4

nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip on;
    gzip_proxied any;
    gzip_types
        text/css
        text/javascript
        text/xml
        text/plain
        application/javascript
        application/x-javascript
        application/json;

    client_max_body_size 32m;

    server {
        listen 80;
        index index.php index.html;
        error_log  /var/log/nginx/error.log;
        access_log /var/log/nginx/access.log;
        root /var/www/public;

        location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
            access_log off;
            expires max;
            log_not_found off;
        }

        # Remove index.php$
        if ($request_uri ~* "^(.*/)index\.php$") {
            return 301 $1;
        }

        location / {
            try_files $uri $uri/ /index.php?$query_string;

            # Remove from everywhere index.php
            if ($request_uri ~* "^(.*/)index\.php(/?)(.*)") {
                return 301 $1$3;
            }
        }

        # Remove trailing slash.
        if (!-d $request_filename) {
            rewrite ^/(.+)/$ /$1 permanent;
        }

        # Clean Double Slashes
        if ($request_uri ~* "\/\/") {
            rewrite ^/(.*) /$1 permanent;
        }

        # enforce NO www
        if ($host ~* ^www\.(.*))
        {
            set $host_without_www $1;
            rewrite ^/(.*)$ $scheme://$host_without_www/$1 permanent;
        }

        location ~* \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass app:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }

        location ~ /\.ht {
            deny all;
        }
    }
}

роут отвечающий за переадресацию

Route::get('/email/verify/{id}/{hash}', function (\Illuminate\Http\Request $request, $id) {
    if(Auth::guest())
    {
        return redirect('/auth/register/verify?next='.Request::fullUrl());
    }
    else
    {
        return redirect('/app/dashboard');
    }
})->name('email-verify')->middleware(['signed']);

В первую очередь пробовал чистить кэш браузера и приложения... не помогло. С nginx я мало знаком...

Понимаю как это выглядит... прошу помощи не до конца разобравшись с nginx. Но я даже не знаю с чего начать... где именно я ошибся или почему происходит зацикливание редиректа. Помогите понять почему это происходит... само приложение и nginx работают в docker контейнерах.


Ответы (1 шт):

Автор решения: vasilisk

Проблему решил. Всё дело в самой ссылке. Нужно было просто экранировать все специальные символы в URL. ссылка на PDF в котором рассказывается как надо экранировать специальные символы -> https://честныйзнак.рф/upload/iblock/d53/Рекомендуемый_алгоритм_экранирования_специальных_символов_в_коде_идентификации_ки.pdf

Однако что конкретно вызвало такое поведения мне не удалось. Вероятно дело в Laravel. Сопоставление адреса с маршрутом отрабатывало некорректно. т.е. laravel при сопоставлении маршрута находил второе вхождение http://mysite/ и работал с ним (брал первый попавшийся роут который совпадал по маршруту, а именно он брал 'email-verify' и снова редиректил на длинный путь с двумя вхождениями http://mysite/ ). Таким образом получался бесконечный цикл.

В пользу этого говорит следующее: В ответе от сервера

General

Request URL: http://mysite/auth/register/verify?next=http://mysite/email/verify/4/4PWWX681MW1sdNe8x3oLRJATQGlWaWDx?signature=fa1a41940dffe9ffc5e6be08ff1d5949d6fe8d04efd2e8aef1bc6b5f6cde58a7
Request Method: GET
Status Code: 301 Moved Permanently
Remote Address: 20.52.148.159:80
Referrer Policy: no-referrer

Response Headers

Connection: keep-alive
Content-Length: 169
Content-Type: text/html
Date: Sat, 21 Aug 2021 23:35:00 GMT
Location: http://mysite/auth/register/verify?next=http://mysite/email/verify/4/4PWWX681MW1sdNe8x3oLRJATQGlWaWDx?signature=fa1a41940dffe9ffc5e6be08ff1d5949d6fe8d04efd2e8aef1bc6b5f6cde58a7
Server: nginx/1.21.1

Т.е. перенаправление точно на такую же ссылку. index.php в исходной ссылке нет а значит и совпадений нет которое бы могло привести к редиректу... (пример https://regex101.com/r/TDxLeH/1/)

А если был бы index.php то регулярное выражение в условии* отработало бы корректно... (пример https://regex101.com/r/fK91U4/1)

*Регулярное выражение в условии

# Remove from everywhere index.php
if ($request_uri ~* "^(.*/)index\.php(/?)(.*)") {
    return 301 $1$3;
}

и даже если бы в ссылке было два index.php (пример https://regex101.com/r/FzPlC6/1) просто для этого пришлось бы сделать два редиректа.

P.S. знающих прошу написать комментарий если я оказался прав... чтобы наверняка знать в чём была причина

P.S.S. надеюсь это кому-то поможет :)

→ Ссылка