Назад | Перейти на главную страницу

Пользовательские заголовки в nginx: сначала войти, потом очистить

Мне нужно разобрать nginx access_log и связывать записи с учетными записями пользователей. Для этого я решил использовать собственный заголовок:

  1. Приложение отправляет настраиваемый заголовок (например, x-userid)
  2. Nginx сохраняет это значение в access_log в настраиваемом формате журнала. $sent_http_x_userid
  3. Заголовок очищается, поэтому клиент не видит его с more_clear_headers 'x-userid'

Ведение журнала работает нормально, я вижу правильные идентификаторы пользователей в access_log. Однако, если я включу очищающую часть, access_log покажет '-' вместо фактического идентификатора пользователя.

Я делаю что-то неправильно? Можно ли записать заголовок из приложения перед его отправкой клиенту, а затем очистить его с помощью nginx?

Есть ли лучший способ заставить эту работу работать? Приложение - PHP7, nginx - 1.10.3

Так как $sent_http_x_userid имя переменной буквально означает, что заголовок был послал клиенту. Когда вы его очистите, nginx не отправит его и не будет переменной $sent_http_x_userid.

Но на самом деле вам нужно зарегистрировать заголовок, который вы получили от восходящего потока. Для этого есть $upstream_http_x_userid переменная, которую вы можете записать в журнал.

И если вы не хотите передавать этот заголовок клиенту, есть proxy_hide_header директива.

Так все вместе могло выглядеть так

log_format coolname '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent [uid=$upstream_http_x_userid] '
                    '"$http_referer" "$http_user_agent"';

server {
    ...
    access_log /var/log/nginx/cool.log coolname;

    location /whatever {
        proxy_pass http://your-app;
        proxy_hide_header x-userid;
    }
}

Я думал, что это будет просто, просто сохраните содержимое заголовка в переменной (используя "set") и используйте эту переменную в вашем log_format, игнорируя очищенный заголовок. Но это с треском провалилось: команда set выполняется до вызова бэкэнда (когда заголовки восходящего потока еще не установлены).

Но использование LUA оказалось успешным:

            set $saved_uid "X";
            header_filter_by_lua_block {
              ngx.var.saved_uid = ngx.var.upstream_http_x_userid;
            }
            more_clear_headers 'x-userid';

и используйте переменную в log_format:

log_format coolname
  '$remote_addr - $remote_user [$time_local] '
  '"$request" $status $body_bytes_sent [uid=$saved_uid] '
  '"$http_referer" "$http_user_agent"';