mod_rewrite의 숨겨진 기능


119

mod_rewrite최근에 특정 측면이 작동하는 방식에 대해 약간의 혼란과 함께 적절한 수의 스레드가 떠 다니는 것 같습니다 . 결과적으로 나는 일반적인 기능에 대한 몇 가지 메모와 아마도 몇 가지 성가신 뉘앙스를 편집했습니다.

사용하면서 겪은 다른 기능 / 일반적인 문제는 무엇입니까 mod_rewrite?


답변:


203

mod_rewrite 규칙을 배치 할 위치

mod_rewrite규칙은 httpd.conf파일 또는 파일 내에 배치 될 수 있습니다 .htaccess. 에 액세스 할 수있는 경우 httpd.conf여기에 규칙을 배치하면 성능 이점이 제공됩니다 ( .htaccess파일이 호출 될 때마다 규칙이 한 번 처리되기 때문에 ).

mod_rewrite 요청 로깅

httpd.conf파일 내에서 로깅을 활성화 할 수 있습니다 (포함 <Virtual Host>).

# logs can't be enabled from .htaccess
# loglevel > 2 is really spammy!
RewriteLog /path/to/rewrite.log
RewriteLogLevel 2

일반적인 사용 사례

  1. 모든 요청을 단일 지점으로 전달하려면 :

    RewriteEngine on
    # ignore existing files
    RewriteCond %{REQUEST_FILENAME} !-f   
    # ignore existing directories
    RewriteCond %{REQUEST_FILENAME} !-d   
    # map requests to index.php and append as a query string
    RewriteRule ^(.*)$ index.php?query=$1 
    

    Apache 2.2.16부터 FallbackResource.

  2. 301/302 리디렉션 처리 :

    RewriteEngine on
    # 302 Temporary Redirect (302 is the default, but can be specified for clarity)
    RewriteRule ^oldpage\.html$ /newpage.html [R=302]  
    # 301 Permanent Redirect
    RewriteRule ^oldpage2\.html$ /newpage.html [R=301] 
    

    참고 : 외부 리디렉션은 암시 적으로 302 리디렉션입니다.

    # this rule:
    RewriteRule ^somepage\.html$ http://google.com
    # is equivalent to:
    RewriteRule ^somepage\.html$ http://google.com [R]
    # and:
    RewriteRule ^somepage\.html$ http://google.com [R=302]
    
  3. SSL 강제

    RewriteEngine on
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://example.com/$1 [R,L]
    
  4. 일반적인 플래그 :

    • [R]또는 [redirect]-강제 리디렉션 (기본값은 302 임시 리디렉션)
    • [R=301]또는 [redirect=301]-301 영구 리디렉션 강제
    • [L]또는 [last]-재 작성 프로세스 중지 (일반적인 함정에 대해서는 아래 참고 참조)
    • [NC]또는 [nocase]-일치가 대소 문자를 구분하지 않도록 지정


    긴 형식의 플래그를 사용하는 것이 더 읽기 쉽고 나중에 코드를 읽는 다른 사람들에게 도움이됩니다.

    쉼표로 여러 플래그를 구분할 수 있습니다.

    RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
    

일반적인 함정

  1. mod_alias스타일 리디렉션과 혼합mod_rewrite

    # Bad
    Redirect 302 /somepage.html http://example.com/otherpage.html
    RewriteEngine on
    RewriteRule ^(.*)$ index.php?query=$1
    
    # Good (use mod_rewrite for both)
    RewriteEngine on
    # 302 redirect and stop processing
    RewriteRule ^somepage.html$ /otherpage.html [R=302,L] 
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    # handle other redirects
    RewriteRule ^(.*)$ index.php?query=$1                 
    

    참고 : mod_alias와 함께 사용할 수 mod_rewrite있지만 위와 같이 기본 리디렉션을 처리하는 것보다 더 많은 작업이 필요합니다.

  2. 컨텍스트가 구문에 영향을 미침

    .htaccess파일 내 에서 선행 슬래시는 RewriteRule 패턴에 사용되지 않습니다.

    # given: GET /directory/file.html
    
    # .htaccess
    # result: /newdirectory/file.html
    RewriteRule ^directory(.*)$ /newdirectory$1
    
    # .htaccess
    # result: no match!
    RewriteRule ^/directory(.*)$ /newdirectory$1
    
    # httpd.conf
    # result: /newdirectory/file.html
    RewriteRule ^/directory(.*)$ /newdirectory$1
    
    # Putting a "?" after the slash will allow it to work in both contexts:
    RewriteRule ^/?directory(.*)$ /newdirectory$1
    
  3. [L]은 마지막이 아닙니다! (때때로)

    [L]플래그는 상기 다시 쓰기 규칙 처리를 중지 규칙 세트를 통해 해당 패스 . 그러나 해당 패스에서 URL이 수정되고 .htaccess컨텍스트 또는 <Directory>섹션에있는 경우 수정 된 요청이 URL 구문 분석 엔진을 통해 다시 전달됩니다. 그리고 다음 패스에서 이번에는 다른 규칙과 일치 할 수 있습니다. 당신이 이것을 이해하지 못한다면, 당신의 [L]깃발이 효과가 없었던 것처럼 보입니다 .

    # processing does not stop here
    RewriteRule ^dirA$ /dirB [L] 
    # /dirC will be the final result
    RewriteRule ^dirB$ /dirC     
    

    재 작성 로그는 규칙이 두 번 실행되고 URL이 두 번 업데이트되었음을 ​​보여줍니다.

    rewrite 'dirA' -> '/dirB'
    internal redirect with /dirB [INTERNAL REDIRECT]
    rewrite 'dirB' -> '/dirC'
    

    이 문제를 해결하는 가장 좋은 방법 은 규칙의 모든 추가 처리 (및 후속 패스)를 진정으로 중지하려는 경우 플래그 대신 [END]플래그 ( Apache 문서 참조 )를 사용하는 것입니다 [L]. 그러나 [END]플래그는 Apache v2.3.9 + 에서만 사용할 수 있으므로 v2.2 이하를 사용하는 경우 [L]플래그 만 붙어 있습니다.

    이전 버전 RewriteCond의 경우 URL 구문 분석 엔진의 후속 패스에서 규칙이 일치하지 않도록 명령문에 의존해야합니다 .

    # Only process the following RewriteRule if on the first pass
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule ...
    

    또는 RewriteRule이 httpd.conf요청을 다시 구문 분석하지 않는 컨텍스트 (예 :)에 있는지 확인해야합니다 .


10
야, 모드 재 작성에 대한 인터넷 최고의 기사. 나는 그게 싫어. 내가 mod_rewrite를 얼마나 싫어 하기 때문에 나는 lighttpd 이단자 입니다.
Kent Fredric

3
이것은 내가 지금까지 mod_rewrite에서 찾은 가장 유용한 가이드였습니다. RewriteLog에 대해 알아내는 것만으로도 많은 문제를 해결하는 데 도움이되었고 추적하는 데 며칠이 걸리는 것이 몇 분으로 바뀌 었습니다. (규칙이 작성되었지만 왜 작동하지 않는지 알 수 없었습니다.)
Joe Chin

1 년 된 게시물이지만 SO에서 찾은 더 유용한 것 중 하나입니다.
Erik

3
[L]플래그는 규칙이 현재 처리에서 마지막 이라는 것을 의미합니다. 내부 리디렉션이기 때문에 다시 쓰기가 중지되지 않으므로 다음 htaccess 처리에 dirB적용됩니다 dirC. 혼자서 RewriteRule ^(.*)$ index.php?query=$1는 내부 리디렉션의 무한 루프가됩니다 (실제로 10 회 반복 후에 종료 됨). -1 왜냐하면 [L]이 마지막이 아니라고 제안했기 때문 입니다. 재 작성 프로세스를 종료하는 것이 아니라 마지막 입니다.
kbec

3
RewriteCond %{HTTPS} offHTTPS 연결을 확인하는 데 선호되는 방법 이라고 생각 합니다 (비 SSL 트래픽을 HTTPS로 강제하는 예제에서)
Madbreaks

22

.htaccess에서 발생하는 내부 리디렉션 / 재 작성을 '차단'해야하는 경우

RewriteCond %{ENV:REDIRECT_STATUS} ^$

여기에 설명 된 대로 조건 .


감사합니다. 문제가 해결되었습니다.
마태 복음

저에게도 감사합니다, 생명의 은인!
Benjamin

이것은 실제로 생명의 은인입니다! 사람들은 그것을 더 잘 알고 있어야합니다. 사실, 나는 여기에 오기 전에 내가 읽은 플래그 .*와 관련된 모든 질문에 이것을 제안 할 것 [L]입니다.
Qwerty

나는이에 몇 가지 수정을 보았다 200, !=200, ^., ^$. 분명히 변수는 200리디렉션 을 위해 설정 되지만 다른 페이지 (오류 및 항목)도 값을 설정합니다. 이제 방법은 당신도 확인하는 것이 그것이 경우 is empty, is not empty, is 200또는 is not 200, 당신이 필요에 따라 달라집니다.
Qwerty

18

RewriteBase와의 거래 :

거의 항상 RewriteBase를 설정해야합니다. 그렇지 않으면 아파치는 기본이 디렉토리에 대한 물리적 디스크 경로라고 추측합니다. 따라서 다음과 같이 시작하십시오.

RewriteBase /

아. 그것은 내가 가진 문제를 완전히 해결했습니다. 감사합니다!
Tom Savage

3
어떤 식 으로든 RewriteBase .URL을 동일하게 유지해야 함을 나타내거나 지정한 내용 만 변경하면됩니다.
Jay K

감사합니다. 이것은 귀중한 정보였습니다. :)
AturSams

2
지시문 RewriteBase에서 상대 경로 대체를 사용하는 경우 에만 설정해야합니다 RewriteRule. 상대 경로를 사용하지 않는 것이 좋습니다.
MrWhite

2
이 답변에 동의하지 않습니다. 우리 개발팀에서는 RewriteBase거의 모든 개발자가 그것이 무엇을하는지 오해하므로 아예 피 합니다. @ w3d가 말했듯이 문자를 저장하고 하나의 파일에있는 모든 RewriteRules에 동일한 기준을 적용하려는 경우에만 필요합니다. 당신이 그것을 피한다면 당신의 코드는 다른 사람들에게 더 명확해질 것입니다.
사이먼 이스트

13

기타 함정 :

1- 때때로 MultiViews를 비활성화하는 것이 좋습니다.

Options -MultiViews

나는 모든 MultiViews 기능에 대해 좋은 구절은 아니지만, 속성 중 하나가 내가 찾고 있다고 생각하는 파일에 대한 확장자를 시도하고 '추측'하는 것이기 때문에 활성화되면 mod_rewrite 규칙을 엉망으로 만듭니다. .

설명하겠습니다 : 웹 디렉토리에 2 개의 php 파일, file1.php 및 file2.php가 있고 다음 조건과 규칙을 .htaccess에 추가한다고 가정합니다.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ file1.php/$1 

파일 또는 디렉토리와 일치하지 않는 모든 URL이 file1.php에 의해 확보된다고 가정합니다. 놀라다! 이 규칙은 URL http : // myhost / file2 / somepath에 적용되지 않습니다 . 대신 file2.php 내부로 이동합니다.

무슨 일이 일어나고 있는지 MultiViews는 실제로 원하는 URL이 http : //myhost/file2.php/somepath 라고 자동으로 추측 하여 기꺼이 당신을 데려갔습니다.

이제 방금 무슨 일이 일어 났는지 전혀 알지 못하며, 그 시점에서 mod_rewrite에 대해 알고 있다고 생각했던 모든 것에 의문을 제기하고 있습니다. 그런 다음이 새로운 상황의 논리를 이해하기 위해 규칙을 가지고 놀기 시작하지만 더 많이 테스트할수록 의미가 떨어집니다.

간단히 말해, mod_rewrite가 로직에 가까운 방식으로 작동하도록하려면 MultiView를 끄는 것이 올바른 방향으로 나아가는 단계입니다.

2- FollowSymlinks 활성화

Options +FollowSymLinks 

저것은 세부 사항을 잘 모르지만 여러 번 언급 한 적이 있으니 그냥하세요.


감사합니다 :) / log / activity가 /log.txt/activity로 바뀌는 것과 같은 예기치 않은 놀라움을 발견했습니다 .. 팁 주셔서 감사합니다 :) .. 너무 나쁜 컴퓨터는 우연히 페이스 북에서 모든 여성 동료를 유혹하는 것과 같은 예기치 않은 일이 일어나지 않도록합니다. :)
AturSams 2011 년

1
+FollowSymLinksmod_rewrite모호한 보안상의 이유로 문서 에서 작업에 필수로 언급되어 있습니다.
Joey

여기에있는 두 가지 진술은 매우 걱정됩니다. '모든 MultiViews 기능에 대해 잘 이해하지는 못합니다.하지만 활성화되면 mod_rewrite 규칙이 엉망이된다는 것을 알고 있습니다.'와 '저것, 나는 세부 사항을 잘 모릅니다. 하지만 여러 번 언급 된 것을 보았으니 그냥하세요. ' 나는 당신과 같은 사람들이 당신이 확실하지 않은 것에 대한 답변을 쓰지 않기를 바랍니다.
TheCarver 2013 년

1
@PaparazzoKid : 나는 당신이 백과 사전으로 오해하고 있다고 생각합니다. 함께 일하는 기술에 대한 이해를 쌓기 위해 함께 모이는 사람들의 커뮤니티입니다. 이전의 AW White 및 Joey와 달리 귀하의 의견은 거의 가치가 없습니다. MV와 FSL은 많은 Apache 옵션 중 두 가지입니다. 내 대답은 mod_rw, 특히 일부 옵션과 충돌하고 다른 모듈과 작동하는 별도의 모듈로 작업 할 때 함정에 관한 것입니다. MV가 mod_rw에 어떤 영향을 미치는지 설명하고 + FSL이 인기있는 권장 사항이라고 언급했습니다. Joey는 그것이 실제로 의무적임을 확인했습니다. 테이블에 무엇을 가져 오나요?
Michael Ekoka

감사. 저는 레거시 사이트를 작동시키고 재 작성 규칙을 디버깅하는 데 1 시간의 가장 좋은 부분을 보냈지 만 MultiViews가 모든 것을 재정의하고 있음을 알았습니다.
Andrew McCombe 2014 년

5

방정식은 다음 예를 통해 수행 할 수 있습니다.

RewriteCond %{REQUEST_URI} ^/(server0|server1).*$ [NC]
# %1 is the string that was found above
# %1<>%{HTTP_COOKIE} concatenates first macht with mod_rewrite variable -> "test0<>foo=bar;"
#RewriteCond search for a (.*) in the second part -> \1 is a reference to (.*)
# <> is used as an string separator/indicator, can be replaced by any other character
RewriteCond %1<>%{HTTP_COOKIE} !^(.*)<>.*stickysession=\1.*$ [NC]
RewriteRule ^(.*)$ https://notmatch.domain.com/ [R=301,L]

동적 부하 분산 :

mod_proxy를 사용하여 시스템의 균형을 맞추는 경우 작업자 서버의 동적 범위를 추가 할 수 있습니다.

RewriteCond %{HTTP_COOKIE} ^.*stickysession=route\.server([0-9]{1,2}).*$ [NC]
RewriteRule (.*) https://worker%1.internal.com/$1 [P,L]

4

[L] 플래그를 더 잘 이해하는 것이 좋습니다. [L] 플래그 마지막입니다. 요청이 URL 구문 분석 엔진을 통해 다시 라우팅되는 원인을 이해하면됩니다. 문서에서 ( http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_l ) (강조 내) :

[L] 플래그는 mod_rewrite가 규칙 세트 처리를 중지하도록합니다. 대부분의 컨텍스트에서 이는 규칙이 일치하면 더 이상 규칙이 처리되지 않음을 의미합니다. 이것은 Perl의 마지막 명령 또는 C의 break 명령에 해당합니다.이 플래그를 사용하여 추가 규칙을 고려하지 않고 현재 규칙을 즉시 적용해야 함을 나타냅니다.

.htaccess 파일 또는 <Directory>섹션 에서 RewriteRule을 사용 하는 경우 규칙이 처리되는 방법을 이해하는 것이 중요합니다. 이것의 단순화 된 형태는 일단 규칙이 처리되면 재 작성된 요청이 URL 구문 분석 엔진으로 다시 전달 되어 그것으로 할 수있는 일을 할 수 있다는 것입니다. 재 작성된 요청이 처리<Directory> 될 때.htaccess 파일 또는섹션이 다시 발생할 수 있으므로 규칙 세트가 처음부터 다시 실행될 수 있습니다. 대부분의 경우 규칙 중 하나가 내부 또는 외부 리디렉션으로 인해 요청 프로세스가 다시 시작되는 경우에 발생합니다.

따라서 [L] 플래그 규칙 세트 를 통과 하는 해당 패스에 대한 추가 다시 쓰기 규칙 처리를 중지 합니다. 그러나 [L]로 표시된 규칙이 요청을 수정하고 .htaccess 컨텍스트 또는 <Directory>섹션에있는 경우 수정 된 요청이 URL 구문 분석 엔진을 통해 다시 전달됩니다. 그리고 다음 패스에서 이번에는 다른 규칙과 일치 할 수 있습니다. 무슨 일이 일어 났는지 이해가 안된다면 [L] 플래그를 사용한 첫 번째 다시 쓰기 규칙이 효과가없는 것 같습니다.

이 문제를 해결하는 가장 좋은 방법은 정말로 중지하려는 경우 [L] 플래그 대신 [END] 플래그 ( http://httpd.apache.org/docs/current/rewrite/flags.html#flag_end )를 사용하는 것입니다. 모든 추가 규칙 처리 (및 후속 재분석). 그러나 [END] 플래그는 Apache v2.3.9 +에서만 사용할 수 있으므로 v2.2 이하를 사용하는 경우 [L] 플래그 만 사용됩니다. 이 경우 RewriteCond 문을 사용하여 URL 구문 분석 엔진의 후속 패스에서 규칙이 일치하지 않도록해야합니다. 또는 RewriteRule이 요청을 다시 구문 분석하지 않는 컨텍스트 (예 : httpd.conf)에 있는지 확인해야합니다.


3

또 다른 훌륭한 기능은 rewrite-map-expansions입니다. 처리 할 호스트 / 재 작성이 엄청나게 많은 경우 특히 유용합니다.

키-값 대체와 같습니다.

RewriteMap examplemap txt:/path/to/file/map.txt

그런 다음 다음과 같은 규칙에 매핑을 사용할 수 있습니다.

RewriteRule ^/ex/(.*) ${examplemap:$1}

이 주제에 대한 자세한 정보는 여기에서 찾을 수 있습니다.

http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#mapfunc


사용중인 경우이 기능을 무시하십시오. .htaccess기반 재 작성을 . 이 맥락에서는 작동하지 않습니다.
TerryE 2012 년

2
RewriteMap 지시문은 서버 컨텍스트 (httpd.conf)에서 사용해야하지만 일단 정의되면 .htaccess 파일에서 RewriteRule을 통해 맵을 사용할 수 있습니다.
JaredC

2

mod_rewrite는 URL을 변경하지 않고도 요청 처리 측면을 수정할 수 있습니다 (예 : 환경 변수 설정, 쿠키 설정 등). 이것은 매우 유용합니다.

조건부로 환경 변수를 설정합니다.

RewriteCond %{HTTP_COOKIE} myCookie=(a|b) [NC]
RewriteRule .* - [E=MY_ENV_VAR:%b]

503 응답을 반환합니다. RewriteRule[R]플래그는 비 -3xx 값을 취하고 리디렉션되지 않는 응답을 반환 할 수 있습니다 (예 : 관리되는 다운 타임 / 유지 보수의 경우).

RewriteRule .* - [R=503,L]

503 응답을 반환합니다 ( 리디렉션 자체가 아님).

또한 mod_rewrite는 mod_proxy에 대한 강력한 인터페이스처럼 작동 할 수 있으므로 ProxyPass지시문 을 작성하는 대신이를 수행 할 수 있습니다 .

RewriteRule ^/(.*)$ balancer://cluster%{REQUEST_URI} [P,QSA,L]

의견 : RewriteRules 및 RewriteConds를 사용하여 요청의 거의 모든 가능한 측면을 기반으로 다른 애플리케이션 또는로드 밸런서로 요청을 라우팅하는 것은 매우 강력합니다. 백엔드로가는 도중에 요청을 제어하고 다시 나가는 동안 응답을 수정할 수 있으므로 mod_rewrite는 모든 라우팅 관련 구성을 중앙 집중화 할 수있는 이상적인 장소입니다.

시간을내어 배우십시오. 그만한 가치가 있습니다! :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.