mod_rewrite
최근에 특정 측면이 작동하는 방식에 대해 약간의 혼란과 함께 적절한 수의 스레드가 떠 다니는 것 같습니다 . 결과적으로 나는 일반적인 기능에 대한 몇 가지 메모와 아마도 몇 가지 성가신 뉘앙스를 편집했습니다.
사용하면서 겪은 다른 기능 / 일반적인 문제는 무엇입니까 mod_rewrite
?
답변
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
일반적인 사용 사례
-
모든 요청을 단일 지점으로 전달하려면 :
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
. -
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]
-
SSL 강제
RewriteEngine on RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://example.com/$1 [R,L]
-
일반적인 플래그 :
[R]
또는[redirect]
-강제 리디렉션 (기본값은 302 임시 리디렉션)[R=301]
또는[redirect=301]
-301 영구 리디렉션 강제[L]
또는[last]
-재 작성 프로세스 중지 (일반적인 함정에 대해서는 아래 참고 참조)[NC]
또는[nocase]
-일치가 대소 문자를 구분하지 않도록 지정
긴 형식의 플래그를 사용하는 것이 더 읽기 쉽고 나중에 코드를 읽는 다른 사람들에게 도움이됩니다.
쉼표로 여러 플래그를 구분할 수 있습니다.
RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
일반적인 함정
-
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
있지만 위와 같이 기본 리디렉션을 처리하는 것보다 더 많은 작업이 필요합니다. -
컨텍스트가 구문에 영향을 미침
.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
-
[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
요청을 다시 구문 분석하지 않는 컨텍스트 (예 :)에 있는지 확인해야합니다 .
답변
답변
RewriteBase와의 거래 :
거의 항상 RewriteBase를 설정해야합니다. 그렇지 않으면 아파치는 기본이 디렉토리에 대한 물리적 디스크 경로라고 추측합니다. 따라서 다음과 같이 시작하십시오.
RewriteBase /
답변
기타 함정 :
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
저것은 세부 사항을 잘 모르지만 여러 번 언급 한 적이 있으니 그냥하세요.
답변
방정식은 다음 예를 통해 수행 할 수 있습니다.
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]
답변
[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)에 있는지 확인해야합니다.
답변
또 다른 훌륭한 기능은 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