들어가며: 작은 차이가 큰 문제를 만든다
오늘 아파치 RewriteRule에서 매우 간단해 보이지만 실제로는 중요한 차이를 발견했다.
| |
이 둘의 차이가 뭘까?
쿼리스트링 처리: 직관을 벗어나다
처음 봤을 때의 직관:
/?= 명시적으로 “아무것도 없다” → 쿼리스트링을 버릴 것 같다/= 경로만 지정 → 원래 쿼리스트링이 유지될 것 같다
그런데 실제로는 반대다.
실제 동작
규칙 1 (/?):
요청: /page?foo=bar&baz=qux
결과: https://example.co.jp/
→ 쿼리스트링이 버려진다
규칙 2 (/):
요청: /page?foo=bar&baz=qux
결과: https://example.co.jp/?foo=bar&baz=qux
→ 쿼리스트링이 유지된다
왜 이런 이상한 일이 일어날까?
Apache의 mod_rewrite 문서를 읽으면:
“By default, the query string is passed through unchanged.”
즉, 기본적으로 쿼리스트링은 유지된다.
그래서:
?= 쿼리스트링을 명시적으로 비우겠다 (버리기)/= 아무 지정 안 함 = 기본값 = 쿼리스트링 유지
Apache 2.4의 전환: QSD의 등장
이 복잡함을 해결하기 위해 Apache 2.4부터는 새로운 플래그가 도입된다:
| |
QSD = Query String Discard
이제 의도가 명확하다:
QSD= 쿼리스트링을 명시적으로 버린다- 플래그 없음 = 쿼리스트링을 기본대로 유지한다
Apache 버전별 권장 방식
Apache 2.2 이전
| |
Apache 2.4+
| |
더 나은 실천법
Apache 2.4 이상이면 QSD를 쓰자
- 의도가 명확함
- 유지보수가 쉬움
- 버전 호환성도 좋음
QSA는 이제 선택사항
- 쿼리스트링을 유지하고 싶을 때 명시적으로 쓸 수 있음
- 하지만 기본값이므로 안 써도 됨
의도를 명확히 하자
1 2 3 4 5 6# 좋은 예 RewriteRule ^(.*)$ https://example.co.jp/ [R=302,L,QSD] # 명시적으로 버림 RewriteRule ^(.*)$ https://example.co.jp/ [R=302,L,QSA] # 명시적으로 유지 # 피하기 RewriteRule ^(.*)$ https://example.co.jp/? [R=302,L] # ?는 헷갈림
교훈: 직관이 틀릴 수 있다
오늘 배운 가장 큰 교훈은 **“명시적으로 보이는 것이 실제 의도를 담지 못할 수 있다”**는 것.
웹서버 설정, 특히 URL 리라이트는:
- 예상과 달리 작동할 수 있다
- 버전마다 다를 수 있다
- 문서를 꼼꼼히 읽어야 한다
다음번엔 불확실하면 검색하고, 결과를 확인해야겠다. 😊
참고 자료:
- Apache mod_rewrite 공식 문서: https://httpd.apache.org/docs/current/mod/mod_rewrite.html
- Query String Handling: https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule
- QSD 플래그 (Apache 2.4+): https://httpd.apache.org/docs/current/mod/mod_rewrite.html#flags