Daylogs/Nginx

nginx: URI 중 매칭된 값을 proxy_pass 에 전달하기

ohgyun 2015. 11. 5. 21:02
발생일: 2015.11.05

키워드: nginx, proxy_pass, location, regexp, regex, group, variable, 변수, 정규식 그룹

문제:

location 블럭에 매칭된 값 중에 일부를 프록시 서버의 파라미터로 전달하고자 한다.

예를 들어, 아래와 같이 주소를 전달받은 후에,

http://example.com/user/1234/a/b/c?x=y&x2=y2


프록시 서버로 아래와 같이 전달하고자 한다.

http://localhost:3000/a/b/c?user_id=1234&x=y&x2=y2


해결책:

nginx 문서의 proxy_pass 항목에는 아래처럼 정의되어 있다.



In some cases, the part of a request URI to be replaced cannot be determined:

When location is specified using a regular expression.
In this case, the directive should be specified without a URI.

When the URI is changed inside a proxied location using the rewrite directive, and this same configuration will be used to process a request (break):
location /name/ {
    rewrite    /name/([^/]+) /users?name=$1 break;
    proxy_pass http://127.0.0.1;
}
In this case, the URI specified in the directive is ignored and the full changed request URI is passed to the server.



문서에서 제시한 대로, 두 가지 방법으로 접근할 수 있다.

1. location 블럭을 정규식으로 정의하고 매칭된 값을 이용하는 방법

위 상황엔 아래처럼 location 구문을 정규식으로 작성하고, proxy_pass 에서 매칭된 그룹의 값을 사용하는 방법으로 해결할 수 있다.

location ~* "^/user/([0-9]+)/(.*)$" {
    proxy_pass http://localhost:3000/$2?user_id=$1&${args};
}


- $1: location 구문에 정의되어 있는 ([0-9]+) 그룹에 매칭된 값
- $2: location 구문에 정의되어 있는 (.*) 그룹에 매칭된 값. 파라미터를 포함하지 않는 것에 주의한다.
- $args: $2에는 파라미터가 포함되어 있지 않기 때문에 전달받은 파라미터를 프록시로 같이 전해준다.



location 구문을 정규식으로 작성하고, proxy_pass 에 정규식 그룹이 아닌 URI만 넣는 경우는 허용하지 않는다.

예를 들어, 아래와 같이 룰을 작성했다면,

location ~* "^/user/([0-9]+)/(.*)$" {
    proxy_pass http://localhost:3000/; # 그룹 매칭 없이 URI(/)만 넣은 경우
}

아래와 같은 오류를 만나게 된다.

nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block



2. 블럭 내에서 rewrite 로 URI를 변경한 후, 프록시 서버에 전달하는 방법

아래처럼 location 블럭 내에서 rewrite 구문으로 요청 URI를 변경 후에, 프록시 서버로 변경한 전체 URI를 전달하는 방법으로 해결할 수 있다.

location ^~ /user/ {
    rewrite ^/user/([0-9]+)/(.*)$ /$2?user_id=$1 break;
    proxy_pass http://localhost:3000;
}


- $1: rewrite 구문의 정규식에서 매칭된 ([0-9]+) 그룹
- $2: rewrite 구문의 정규식에서 매칭된 (.*) 그룹. 파라미터를 포함하지 않는다.
- rewrite 이후 현재 블럭에서 프로세싱을 종료하기 위해 break 구문을 명시해준다.
- proxy_pass 의 마지막에 URI가 포함되어 있지 않기 때문에, 전체 URI가 프록시 서버로 전달되며,
  요청에 포함된 나머지 파라미터는 nginx에서 자동으로 붙여 전달한다.



* 매칭된 값을 변수로 활용하기

매칭된 값을 파라미터가 뿐 아니라 헤더나 다른 디렉티브 등에 활용하기 위해 변수로 담아둘 수 있다.
아래처럼 PCRE 패턴으로 매칭시킬 수 있다.

location ~* "^/user/(?<user_id>[0-9]+)/(.*)$" {
    proxy_pass http://localhost:3000/$2?user_id=${user_id}&${args};
}


rewrite 구문을 사용하는 경우에도 동일하게 사용할 수 있다.

location ^~ /user/ {
    rewrite ^/user/(?<user_id>[0-9]+)/(.*)$ /$2?user_id=${user_id} break;
    proxy_pass http://localhost:3000;
}
반응형