nginx query string encoding problem
요구사항
- ap서버에서 nginx를 통해서 외부 nas에 저장된 첨부파일을 가져와야하는 요건
http://172.16.120.206:8051/?url=http%3A%2F%2Ftest.com%2Ftalkm%2FoY7TLhEsug%2FjqKpQBa0HtbvGdRjirexV0%2Fi_504b25b09b19.jpg
- nginx 서버 : 172.16.120.206:8051
- 파라미터 url을 AP서버에서 feignclient로 nginx 통해 호출해서 첨부파일을 읽어봐야 함
- feign으로 호출하기 전에는 인코딩이 되어있지 않지만, feign라이브러리 내 httpclient를 구현하는 클래스에서 인코딩이 시킨후 호출되고 있었습니다.
이런 형태의 url일 경우, regex로 matching시키는게 간단하지 않습니다.
dns가 변경될 가능성도 크고
보안 url이기 때문에 리소스 path가 유동적일 가능성도 큽니다.
try1..
nginx에서 $args_url을 받자마자 proxy_pass하는 방법으로 젤 먼저 해봤습니다
try1-problem
url에 인코딩된 특수문자로 에러가 발생합니다.
try2..
슬래시가 한번일 경우 한번만 matching시키고 나머지는 (.*)$로 잡으면되는데
location ~* ^.+\.(jpg|jpeg|gif|png|pdf|txt|bmp)$ {
이렇게 작성하면 조건을 타지도 못한다. 이유는 query_string의 내용으로 location을 matching시킬수 없다고 한다.
try3..
경로가 여러개 일 경우는 억지로 한다면 이렇게 하게 됩니다.
if ($args ~ (test.com)%2F(.*)%2F(.*)%2F(.*)%2F(.*)$) {
set $aaa $1;
set $bbb $2/$3/$4/$5;
rewrite . /$bbb break;
proxy_pass http://$aaa;
}
try3-problem
앞서 설명했듯이 url자체가 유동적일 가능성이 크기 때문에 위의 방법은 사용하면 안 됩니다.
try4..
그래서 찾던 중 njs모듈 설치를 하면 된다고 해서 적용해봤습니다.
Redirect to the encode url present in query parameter in NGINX
- 모듈 설치
[root@victory-dev-106 conf.d]# sudo yum install nginx-module-njs
- nginx.conf에 load_module 추가
load_module modules/ngx_http_js_module.so;
- http.js 생성
function decoded_url(r) {
return decodeURIComponent(r.args.url);
}
export default {decoded_url};
- js로 파싱한 결과 set하는걸 http {} 블록 하위에 선언
http {
js_import http.js;
js_set $decoded_url http.decoded_url;
include /etc/nginx/conf.d/*.conf;
server {
listen 8051;
server_name localhost;
charset utf-8;
rewrite_log on;
location = / {
if ($decoded_url ~ http[s]?:\/?\/?([^\/]+)(.*)$) {
set $aaa $1;
set $bbb $2;
rewrite . $bbb break;
proxy_pass http://$aaa;
}
proxy_redirect off;
error_log /var/log/nginx/dn-m.img.error.log debug;
}
}
}
오프라인으로 njs 설치하고자 하면, nginx설치부터 njs포함시켜서 수동설치
https://jcartw.medium.com/how-to-install-nginx-from-source-with-njs-javascript-module-443e8e3a0cf2
—> 대신 add-module이 configure된 것이라 nginx.conf에 load_module안해도 됨
try4-problem
njs를 설치하면 인코딩된 url을 디코드시켜주기 때문에 문제가 해결됩니다.
하지만 운영중인 사이트에 모듈을 설치하기엔 부담이 있었습니다.
try5..(solved)
좀더 검색해보니 아래 블로그를 발견!!
https://lng1982.tistory.com/341
—> path나 body에 있는 string은 무조건 인코딩된다고 합니다.
그래서 저는 url을 header에 넣는 것으로 꼼수를 부려봤습니다.
feign으로 nginx호출할 때, url을 XAttachUrl 헤더에 셋팅하고 호출
[feign client class]
@FeignClient(
contextId = "client.ThirdPartyGatewayFileClient",
name = "${crema.thirdparty.thirdparty-gateway.name}",
configuration = {MultipartSupportConfig.class},
primary = false
)
public interface ThirdPartyGatewayFileClient {
@GetMapping(value = "attach/download")
ResponseEntity<byte[]> download(@RequestHeader("XAttachUrl") String url);
}
- nginx쪽으로 http://172.16.120.206:8051/attach/download를 호출하면서 헤더에 url을 실어보냅니다.
[nginx.conf]
location ~* /attach/download {
resolver 8.8.8.8;
if ($http_XAttachUrl ~ http[s]?:\/?\/?([^\/]+)(.*)$) {
set $part1 $1;
set $part2 $2;
rewrite . $part2 break;
proxy_pass http://$part1;
}
proxy_redirect off;
error_log /var/log/nginx/dn-m.img.error.log debug;
}
- $part1은 도메인
- $part2는 도메인 이후의 path, 파라미터 등의 나머지
add. 23.06.10
- 이번엔 url에 쿼리스트링이 포함되면서 header에 있는 query string의 ? 물음표도 인코딩되어 404 에러가 발생하고 있었습니다.
- nginx의 error log를 debug로 변경하면 아래처럼 물음표가 %3F로 변환되어 호출되는 것을 확인할 수 있습니다.
"GET /dna/mBOdC/oZ07liuNex/S0hbYfYvbw9JRvhEk6LC7b/i_0468034a7859.jpg%3Fcredential=zf3biCPbmWRjbqf40YG HTTP/1.0
Host: aaa.net
Connection: close
XAttachUrl: https://aaa.net/dna/mBOdC/oZ07liuNex/S0hbYfYvbw9JRvhEk6LC7b/i_0468034a7859.jpg?credential=zf3biCPbmWRjbqf40YG
User-Agent: PostmanRuntime/7.32.2
Accept: */*
- 그래서 어플리케이션에서 호출할 때 헤더를 하나더 추가해서 쿼리스트링만 별도의 헤더변수로 전달하도록 했습니다.
- XAttachQuery 헤더 변수 추가
[nginx.conf]
location ~* /attach/download {
resolver 8.8.8.8;
if ($http_XAttachUrl ~ http[s]?:\/?\/?([^\/]+)(.*)$) {
set $part1 $1;
set $part2 $2;
rewrite . $part2?$http_XAttachQuery break;
proxy_pass http://$part1;
}
proxy_redirect off;
error_log /var/log/nginx/dn-m.img.error.log debug;
}