참조 : mod_rewrite, URL 재 작성 및 "pretty 링크"설명


142

"예쁜 링크"는 자주 요청되는 주제이지만 그에 대한 설명은 거의 없습니다. mod_rewrite 는 "예쁜 링크"를 만드는 한 가지 방법이지만, 복잡하고 구문이 매우 간결하고 이해하기 어려우며이 문서는 HTTP의 특정 수준의 숙련도를 가정합니다. 누군가 "예쁜 링크"가 어떻게 작동하는지 mod_rewrite를 사용하여 어떻게 만들 수 있는지 간단한 용어로 설명 할 수 있습니까?

클린 URL에 대한 다른 일반적인 이름, 별명, 용어 : RESTful URL, 사용자 친화적 URL, SEO 친화적 URL, 슬러 깅 및 MVC URL (아마도 잘못된 이름)


2
슬러그 또는 슬러 깅은 예쁜 URL의 또 다른 일반적인 별칭입니다.
Mike B

2
@Mike 일종이지만 슬러그는 종종 예쁜 URL 의 일부입니다 . 슬러그는 예를 들어 기사의 헤드 라인이 URL 친화적 인 형식으로 바뀌어 기사의 식별자 역할을하는 경우에 매우 구체적입니다. 그래서 reference-mod-rewrite-url-rewriting-explained슬러그이며, /questions/20563772/reference-mod-rewrite-url-rewriting-explained예쁜 URL입니다.
deceze

2
나는 자주 묻는 질문의 대부분을 다루기 때문에이 질문에 대한 링크를 포함 하도록 .htaccessand mod-rewrite태그를 업데이트해야 한다고 생각합니다 . 생각?
Mike Rockétt

답변:


110

mod_rewrite의 기능을 이해하려면 먼저 웹 서버의 작동 방식을 이해해야합니다. 웹 서버는 HTTP 요청에 응답 합니다 . 가장 기본적인 수준의 HTTP 요청은 다음과 같습니다.

GET /foo/bar.html HTTP/1.1

이것은 URL /foo/bar.html 을 요청하는 웹 서버에 대한 브라우저의 간단한 요청입니다 . 파일을 요청하지 않고 임의의 URL 만 요청한다는 점을 강조하는 것이 중요합니다 . 요청은 다음과 같습니다.

GET /foo/bar?baz=42 HTTP/1.1

이것은 URL에 대한 유효한 요청이며 파일과는 더 관련이 없습니다.

웹 서버는 포트에서 수신하는 응용 프로그램으로, 해당 포트에서 들어오는 HTTP 요청을 수락하고 응답을 반환합니다. 웹 서버는 사용자가 응답하도록 구성한 방식으로 어떤 방식 으로든 요청에 ​​응답 할 수 있습니다. 이 응답은 파일이 아니며 디스크의 실제 파일과 관련이 있거나 없을 수 있는 HTTP 응답 입니다. 웹 서버는 아파치 일 필요는 없으며, 지속적으로 실행되고 HTTP 요청에 응답하는 포트에 연결된 프로그램 일 뿐인 다른 많은 웹 서버가 있습니다. 직접 쓸 수 있습니다. 이 단락은 URL이 파일과 직접 동일한 개념으로 이해하기 위해 작성되었습니다. 이해해야합니다. :)

대부분의 웹 서버의 기본 구성은 하드 디스크의 URL과 일치하는 파일을 찾는 것입니다. 서버 의 문서 루트 가로 설정되어 있으면 /var/www파일 /var/www/foo/bar.html이 존재 하는지 확인하여 파일 을 제공 할 수 있습니다. 파일이 ".php"로 끝나면 PHP 인터프리터를 호출 한 다음 결과 반환합니다. 이 모든 연관성을 완전히 구성 할 수 있습니다. 웹 서버가 PHP 인터프리터를 통해 파일을 실행하기 위해 파일이 ".php"로 끝나지 않아도되며 URL은 디스크의 특정 파일과 일치하지 않아도 발생합니다.

mod_rewrite는 내부 요청 처리 를 다시 쓰는 방법 입니다. 웹 서버가 URL에 대한 요청을 수신 하면 웹 서버가 디스크에서 파일과 일치하는 파일을 찾기 전에 해당 URL을 다른 것으로 다시 작성할/foo/bar 수 있습니다 . 간단한 예 :

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

이 규칙은 요청이 "/ foo / bar"와 일치 할 때마다 "/ foo / baz"로 다시 작성합니다. 그러면 요청이 요청 된 것처럼 처리 /foo/baz됩니다. 다음과 같은 다양한 효과에 사용할 수 있습니다.

RewriteRule (.*) $1.html

이 규칙 일치 아무것도 ( .*) 및 캡처는 그것을 ( (..)), 다음은 ".html 중에서"를 추가 할 재 작성. 즉, /foo/bar요청 된 URL 인 경우 /foo/bar.html요청 된 것처럼 처리됩니다 . 정규식 일치, 캡처 및 대체에 대한 자세한 내용은 http://regular-expressions.info 를 참조하십시오 .

자주 발생하는 또 다른 규칙은 다음과 같습니다.

RewriteRule (.*) index.php?url=$1

이것은 다시 무엇이든 일치시키고 urlquery 매개 변수 에 원래 요청 된 URL을 추가하여 index.php 파일에 다시 씁니다 . 즉, 들어오는 모든 요청에 ​​대해 index.php 파일이 실행 되고이 파일은의 원래 요청에 액세스 $_GET['url']할 수 있으므로 원하는 모든 작업을 수행 할 수 있습니다.

기본적으로 이러한 다시 쓰기 규칙을 웹 서버 구성 파일에 넣습니다 . 또한 아파치는 .htaccess문서 루트 (예 : .php 파일 옆) 에있는 파일에 파일을 넣을 수 있도록합니다 * .

* 기본 Apache 구성 파일에서 허용하는 경우 선택 사항이지만 종종 사용됩니다.

mod_rewrite가하지 않는

mod_rewrite가 모든 URL을 마술처럼 아름답게 만들지는 않습니다. 이것은 일반적인 오해입니다. 웹 사이트에이 링크가있는 경우 :

<a href="https://stackoverflow.com/my/ugly/link.php?is=not&amp;very=pretty">

mod_rewrite가 그것을 예쁘게 만들기 위해 할 수있는 일은 없습니다. 이 링크를 예쁘게 만들려면 다음을 수행해야합니다.

  1. 링크를 예쁜 링크로 변경하십시오.

    <a href="https://stackoverflow.com/my/pretty/link">
    
  2. 서버에서 mod_rewrite를 /my/pretty/link사용하여 위에서 설명한 방법 중 하나를 사용 하여 URL에 대한 요청을 처리하십시오 .

mod_substitute나가는 HTML 페이지와 포함 된 링크를 변환하는 데 함께 사용할 수 있습니다 . HTML 리소스를 업데이트하는 것보다 일반적으로 더 많은 노력이 필요합니다.

mod_rewrite가 수행 할 수있는 작업과 여러 번의 다시 쓰기 연결, 완전히 다른 서비스 또는 시스템에 대한 요청 프록시, 특정 HTTP 상태 코드를 응답으로 반환, 요청 리디렉션 등을 포함하여 만들 수있는 매우 복잡한 일치 규칙이 있습니다. 매우 강력하고 사용할 수 있습니다. 기본 HTTP 요청-응답 메커니즘을 이해하면 좋습니다. 자동으로 링크를 예쁘게 만들지 는 않습니다 .

가능한 모든 플래그 및 옵션에 대해서는 공식 문서 를 참조하십시오 .


6
발송자에게 다시 쓰는 바람직한 방법 으로 버전 2.2.16에 도입 된 FallbackResource 지시문을 언급 할 수 있습니다.
Darsstar

78

deceze의 답변 을 확장 하기 위해 다른 mod_rewrite 기능에 대한 몇 가지 예와 설명을 제공하고 싶었습니다.

예 아래의 모든 이미 포함했다고 가정 RewriteEngine On당신의 .htaccess파일.

재 작성 예

이 예제를 보자.

RewriteRule ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ /blog/index.php?id=$1&title=$2 [NC,L,QSA]

규칙은 4 개의 섹션으로 나뉩니다.

  1. RewriteRule -다시 쓰기 규칙을 시작합니다
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ -이 패턴을 패턴이라고하지만 규칙의 왼쪽이라고하겠습니다.
  3. blog/index.php?id=$1&title=$2 -대체 규칙 또는 재 작성 규칙의 오른쪽-재 작성하려는 항목
  4. [NC,L,QSA] 다시 쓰기 규칙에 대한 플래그이며 쉼표로 구분되며 나중에 자세히 설명하겠습니다.

위의 다시 쓰기를 사용하면 비슷한 것으로 링크 할 수 /blog/1/foo/있으며 실제로로드 /blog/index.php?id=1&title=foo됩니다.

규칙의 왼쪽

  • ^페이지 이름의 시작을 나타내므로 다시 example.com/blog/...쓰지만 다시 쓰지 는 않습니다.example.com/foo/blog/...
  • (…)괄호 세트 는 규칙의 오른쪽에서 변수로 캡처 할 수있는 정규식을 나타냅니다. 이 예에서 :
    • 첫 번째 대괄호 세트는- ([0-9]+)길이가 최소 1 자이고 숫자 값만있는 문자열 (예 : 0-9)과 일치합니다. 이것은 $1규칙의 오른쪽에서 참조 할 수 있습니다
    • 괄호의 두 번째 세트는 숫자 (AZ, az, 0-9)를 포함, 길이가 1 개 문자의 최소 문자열을 일치하거나 -또는 +(주는 +이것은로 실행됩니다 그것을 탈출하지 않고 같이 백 슬래시로 이스케이프 정규식 반복 문자 ). 이것은 $2규칙의 오른쪽에서 참조 할 수 있습니다
  • ?앞의 문자가 있으므로이 경우, 선택적 수단 모두 /blog/1/foo//blog/1/foo같은 장소에 다시 것
  • $ 이것은 우리가 일치시키고 싶은 문자열의 끝을 나타냅니다

플래그

재 작성 규칙 끝에 특정 조건을 지정하기 위해 대괄호 안에 추가되는 옵션입니다. 다시 말하지만, 문서 에서 읽을 수있는 많은 다른 플래그가 있지만 더 일반적인 플래그 중 일부를 살펴 보겠습니다.

NC

대소 문자 없음 플래그는 다시 쓰기 규칙이 대소 문자를 구분하지 않음을 의미하므로 위의 예제 규칙의 경우 /blog/1/foo//BLOG/1/foo/(또는이 변형이 모두) 일치 함을 의미합니다.

L

마지막 플래그는 이것이 처리되어야하는 마지막 규칙임을 나타냅니다. 이는이 규칙이 일치하는 경우에만 현재 다시 쓰기 처리 실행에서 더 이상 규칙이 평가되지 않음을 의미합니다. 규칙이 일치하지 않으면 평소대로 다른 모든 규칙이 시도됩니다. L플래그를 설정하지 않으면 나중에 다음 규칙이 다시 작성된 URL에 적용됩니다 .

END

Apache 2.4부터 [END]플래그 를 사용할 수도 있습니다 . 이것과 일치하는 규칙은 추가 별칭 / 다시 쓰기 처리를 완전히 종료합니다. ( [L]예를 들어 하위 디렉토리에 또는 외부 디렉토리를 다시 쓸 때와 같이 플래그가 종종 두 번째 라운드를 트리거 할 수 있습니다.)

QSA

쿼리 문자열 추가 플래그를 사용하면 추가 변수를 지정된 URL로 전달하여 원래 get 매개 변수에 추가 할 수 있습니다. 이 예에서는 /blog/1/foo/?comments=15로드가/blog/index.php?id=1&title=foo&comments=15

R

이 플래그는 위 예제에서 사용한 것이 아니지만 언급 할 가치가있는 것으로 생각됩니다. 이를 통해 상태 코드를 포함하는 옵션 (예 :)을 사용하여 http 리디렉션을 지정할 수 있습니다 R=301. 예를 들어, / myblog /에서 / blog /로 301 리디렉션을 수행하려면 다음과 같은 규칙을 작성하면됩니다.

RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]

재 작성 조건

재 작성 조건은 좀 더 구체적인 상황에 대한 재 작성을 지정할 수 재 작성이 훨씬 더 강력합니다. documentation 에서 읽을 수있는 조건이 많이 있지만 몇 가지 일반적인 예를 터치하고 설명합니다.

# if the host doesn't start with www. then add it and redirect
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

이는 매우 일반적인 관행이며 도메인 www.이없는 경우 (예 : 도메인 이없는 경우) 301 리디렉션을 실행합니다. 예를 들어,로드 http://example.com/blog/하면http://www.example.com/blog/

# if it cant find the image, try find the image on another domain
RewriteCond %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)$ http://www.example.com/$1 [L]

이것은 일반적이지 않지만 파일 이름이 서버에 존재하는 디렉토리 또는 파일 인 경우 실행되지 않는 규칙의 좋은 예입니다.

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC] 파일 확장자가 jpg, jpeg, gif 또는 png (대소 문자 구분 안 함) 인 파일에 대해서만 다시 쓰기를 실행합니다.
  • %{REQUEST_FILENAME} !-f 파일이 현재 서버에 있는지 확인하고 파일이 없으면 다시 쓰기를 실행합니다.
  • %{REQUEST_FILENAME} !-d 파일이 현재 서버에 있는지 확인하고 파일이 없으면 다시 쓰기를 실행합니다.
  • 다시 쓰기는 다른 도메인에 동일한 파일을로드하려고 시도합니다

39

참고 문헌

스택 오버플로가 많은 시작하는 다른 훌륭한 자원을 :

그리고 새로 온 친절한 정규식 개요 :

자주 사용되는 자리 표시 자

  • .*빈 문자열까지도 일치합니다. 이 패턴을 모든 곳에서 사용하고 싶지는 않지만 종종 마지막 대체 규칙에서 사용합니다.
  • [^/]+경로 세그먼트에 더 자주 사용됩니다. 슬래시 이외의 항목과 일치합니다.
  • \d+ 숫자 문자열과 만 일치합니다.
  • \w+영숫자와 일치합니다. 기본적으로 약어입니다 [A-Za-z0-9_].
  • [\w\-]+"슬러그"스타일 경로 세그먼트의 경우 문자, 숫자, 대시 - _
  • [\w\-.,]+마침표와 쉼표를 추가합니다. charclasses \-에서 이스케이프 된 대시를 선호하십시오 […].
  • \.리터럴 마침표를 나타냅니다. 그렇지 않으면 .외부는 […]모든 기호에 대한 자리 표시 자입니다.

이러한 각 자리 표시자는 일반적 (…)으로 캡처 그룹 으로 괄호로 묶습니다. 그리고 전체 패턴은 종종 ^………$시작 + 끝 마커에 있습니다. "패턴"을 인용하는 것은 선택 사항입니다.

규칙을 다시 작성

다음 예제는 PHP 중심이며 조금 더 점증 적이며 유사한 경우에 더 쉽게 적용 할 수 있습니다. 그것들은 요약 일 뿐이며, 종종 더 많은 변형이나 상세한 Q & A에 연결됩니다.

  • 정적 매핑
    /contact,/about

    내부 파일 체계로 몇 개의 페이지 이름을 줄이는 것이 가장 간단합니다.

     RewriteRule ^contact$  templ/contact.html
     RewriteRule ^about$    about.php
    
  • 숫자 식별자
    /object/123

    http://example.com/article/531기존 PHP 스크립트 와 같은 바로 가기를 소개 하는 것도 쉽습니다. 숫자 자리 표시자는 $_GET매개 변수 로 다시 매핑 할 수 있습니다 .

     RewriteRule ^article/(\d+)$    article-show.php?id=$1
     #                      └───────────────────────────┘
    
  • 슬러그 스타일 플레이스 홀더
    /article/with-some-title-slug

    /article/title-string자리 표시자를 허용하도록 해당 규칙을 쉽게 확장 할 수 있습니다 .

     RewriteRule ^article/([\w-]+)$    article-show.php?title=$1
     #                       └────────────────────────────────┘
    

    참고 스크립트가 있어야 할 수 있습니다 (또는 적용 할 수) 다시 데이터베이스 식별자에 그 제목을 매핑 할 수 있습니다. 규칙만으로는 정보가 허술한 정보를 만들거나 추측 할 수 없습니다.

  • 숫자 접두사가있는 슬러그
    /readable/123-plus-title

    따라서 /article/529-title-slug실제로 사용되는 혼합 경로가 종종 표시 됩니다.

     RewriteRule ^article/(\d+)-([\w-]+)$    article.php?id=$1&title=$2
     #                      └───────────────────────────────┘
    

    title=$2스크립트는 일반적으로 데이터베이스 ID를 사용하기 때문에 어쨌든 전달을 건너 뛸 수 있습니다 . 는 -title-slug임의의 URL 장식되었다.

  • 대체 목록과의 균일 성
    /foo/… /bar/… /baz/…

    여러 가상 페이지 경로에 대해 유사한 규칙이있는 경우 |다른 목록 과 일치시키고 압축 할 수 있습니다 . 그리고 다시 내부 GET 매개 변수에 다시 할당하십시오.

     #                               ┌─────────────────────────┐
     RewriteRule ^(blog|post|user)/(\w+)$  disp.php?type=$1&id=$2
     #               └───────────────────────────────────┘
    

    RewriteRule너무 복잡해지면 개별으로 나눌 수 있습니다 .

  • 관련 URL을 다른 백엔드로 디스패치
    /date/SWITCH/backend

    대체 목록의보다 실용적인 사용은 요청 경로를 고유 한 스크립트로 맵핑하는 것입니다. 예를 들어 날짜를 기준으로 이전 및 최신 웹 응용 프로그램에 균일 한 URL을 제공하려면 다음을 수행하십시오.

     #                   ┌─────────────────────────────┐
     #                   │                 ┌───────────┼───────────────┐
     RewriteRule ^blog/(2009|2010|2011)/([\d-]+)/?$ old/blog.php?date=$2
     RewriteRule ^blog/(\d+)/([\d-]+)/?$  modern/blog/index.php?start=$2
     #                          └──────────────────────────────────────┘
    

    이것은 2009-2011 게시물을 한 스크립트에 다시 매핑하고 다른 모든 연도는 다른 처리기에 암시 적으로 다시 매핑합니다. 노트 보다 구체적인 규칙이 먼저오고 . 각 스크립트는 다른 GET 매개 변수를 사용할 수 있습니다.

  • /경로 슬래시 이외의 다른 구분 기호
    /user-123-name

    가상 디렉토리 구조를 시뮬레이션하기 위해 가장 일반적으로 RewriteRules가 표시됩니다. 그러나 창의력을 발휘하지 않아도됩니다. -분할 또는 구조에 하이픈을 사용할 수도 있습니다 .

     RewriteRule ^user-(\d+)$    show.php?what=user&id=$1
     #                   └──────────────────────────────┘
     # This could use `(\w+)` alternatively for user names instead of ids.
    

    또한 일반적인 /wiki:section:Page_Name구성표 :

     RewriteRule ^wiki:(\w+):(\w+)$  wiki.php?sect=$1&page=$2 
     #                   └─────┼────────────────────┘       │
     #                         └────────────────────────────┘
    

    때때로 그것은 사이의 대체에 적합 /-delimiters 및 :또는 .심지어 같은 규칙이있다. 또는 두 개의 RewriteRules를 다시 사용하여 변형을 다른 스크립트에 매핑하십시오.

  • 선택적 후행 /슬래시
    /dir=/dir/

    디렉토리 스타일 경로를 선택할 때 최종 경로 유무에 관계없이 경로에 도달 할 수 있습니다 /

     RewriteRule ^blog/([\w-]+)/?$  blog/show.php?id=$1
     #                         ┗┛
    

    이제이 손잡이 모두 http://example.com/blog/123/blog/123/. 이 /?$접근 방식은 다른 RewriteRule에 쉽게 추가 할 수 있습니다.

  • 가상 경로를위한 유연한 세그먼트
    .*/.*/.*/.*

    발생하는 대부분의 규칙은 제한된 /…/리소스 경로 세그먼트 세트 를 개별 GET 매개 변수에 맵핑합니다 . 그러나 일부 스크립트 는 다양한 옵션을 처리합니다 . Apache regexp 엔진은 임의의 수의 옵션을 선택적으로 허용하지 않습니다. 그러나 쉽게 규칙 블록으로 쉽게 확장 할 수 있습니다.

     Rewriterule ^(\w+)/?$                in.php?a=$1
     Rewriterule ^(\w+)/(\w+)/?$          in.php?a=$1&b=$2
     Rewriterule ^(\w+)/(\w+)/(\w+)/?$    in.php?a=$1&b=$2&c=$3
     #              └─────┴─────┴───────────────────┴────┴────┘
    

    최대 5 개의 경로 세그먼트가 필요한 경우이 체계를 5 개의 규칙으로 복사하십시오. 물론보다 구체적인 [^/]+자리 표시자를 각각 사용할 수 있습니다 . 여기서 순서는 겹치지 않기 때문에 중요하지 않습니다. 따라서 가장 자주 사용되는 경로를 먼저 갖는 것이 좋습니다.

    또는 ?p[]=$1&p[]=$2&p[]=3스크립트가 단순히 사전 분할을 선호하는 경우 쿼리 문자열을 통해 PHP 배열 매개 변수를 활용할 수 있습니다 . (포괄적 인 규칙 만 사용하고 스크립트 자체가 REQUEST_URI에서 세그먼트를 확장하도록하는 것이 더 일반적이지만)

    참조 : 어떻게 쿼리 문자열 키 - 값 쌍으로 내 URL 경로 세그먼트를 변환합니까?

  • 선택적 세그먼트
    prefix/opt?/.*

    일반적인 변형은 규칙 내에 선택적 접두사 를 사용 하는 것입니다. 정적 문자열 또는 더 제한된 자리 표시자가있는 경우 일반적으로 의미가 있습니다.

      RewriteRule ^(\w+)(?:/([^/]+))?/(\w+)$  ?main=$1&opt=$2&suffix=$3
    

    이제 더 복잡한 패턴은 (?:/([^/])+)?단순히 캡처하지 않는 (?:…) 그룹을 감싸고 선택 사항으로 만듭니다 )?. 포함 된 자리 표시자는 replacement ([^/]+)pattern $2이지만 중간 /…/경로 가 없으면 비어 있습니다 .

  • 나머지를 캡처
    /prefix/123-capture/…/*/…whatever…

    앞에서 말했듯이 너무 일반적인 재 작성 패턴은 원하지 않습니다. 그러나 정적 및 특정 비교를 .*때때로 결합하는 것이 합리적 입니다.

     RewriteRule ^(specific)/prefix/(\d+)(/.*)?$  speci.php?id=$2&otherparams=$2
    

    이것은 /…/…/…후행 경로 세그먼트를 옵션 화했습니다 . 물론,이를 처리하기 위해 처리 스크립트가 필요하며 추출 된 매개 변수 자체를 variabl-ify ( 웹- "MVC" 프레임 워크가하는 것)가 필요합니다.

  • 후행 파일 "확장명"
    /old/path.HTML

    URL에는 실제로 파일 확장자가 없습니다. 이 전체 참조 내용은 다음과 같습니다 (= URL은 가상 로케이터이며 반드시 직접 파일 시스템 이미지는 아님). 그러나 이전에 1 : 1 파일 매핑이 있었다면 더 간단한 규칙을 만들 수 있습니다 .

     RewriteRule  ^styles/([\w\.\-]+)\.css$  sass-cache.php?old_fn_base=$1
     RewriteRule  ^images/([\w\.\-]+)\.gif$  png-converter.php?load_from=$2
    

    다른 일반적인 용도는 .html최신 .php처리기로 경로를 다시 매핑 하거나 개별 (실제 / 실제) 파일에 대해서만 디렉토리 이름 별칭을 지정하는 것입니다.

  • 탁구 (직접 리디렉션 및 재 작성)
    /ugly.html← →/pretty

    따라서 어느 시점에서 deceze요약 된 것처럼 예쁜 링크 만 전달하도록 HTML 페이지를 다시 작성합니다 . 그 사이에도 여전히 이전 경로에 대한 요청이 표시 될 수 있으며 때로는 책갈피에서도 수신됩니다 . 으로 해결 , 당신은 / 화면에 브라우저를 탁구 - 핑 새로운 URL을 설정할 수 있습니다.

    이 일반적인 속임수는 들어오는 URL이 더 이상 사용되지 않는 추악한 이름 지정 체계를 따를 때마다 30x / 위치 리디렉션을 보내는 것 입니다. 브라우저 것이다 다음 rerequest 나중에 원본 또는 새 위치 (단지 내부적으로) 다시 작성하는 새 / 꽤 URL.

     # redirect browser for old/ugly incoming paths
     RewriteRule ^old/teams\.html$ /teams [R=301,QSA,END]
    
     # internally remap already-pretty incoming request
     RewriteRule ^teams$ teams.php        [QSA,END]
    

    이 예제 가 안전하게 대체 하는 [END]대신 사용하는 방법에 유의하십시오 [L]. 이전 Apache 2.2 버전의 경우 쿼리 문자열 매개 변수를 다시 매핑하는 것 외에도 다른 해결 방법을 사용할 수 있습니다. 예를 들어 ugly를 예쁜 URL로 리디렉션하고 무한 루프없이 ugly 경로로 다시 매핑하십시오.

  • 패턴의 공백
    /this+that+

    그것은 아니다 브라우저의 주소 표시 줄에,하지만 당신은 URL에 공백을 사용할 수 있습니다. 다시 쓰기 패턴의 경우 백 슬래시 이스케이프 \␣공백을 사용 하십시오. 그렇지 않으면 "전체 패턴 또는 대체를 인용하십시오.

     RewriteRule  "^this [\w ]+/(.*)$"  "index.php?id=$1"  [L]
    

    클라이언트 는 공백 이 +있거나 %20공백으로 URL을 직렬화합니다 . 그러나 RewriteRules에서는 모든 상대 경로 세그먼트에 대한 리터럴 문자로 해석됩니다.

자주 복제 :

일반적인 .htaccess함정

이제 소금 한알로 이것을 가져 가십시오. 모든 조언을 모든 상황에 대해 일반화 할 수있는 것은 아닙니다. 이것은 잘 알려진 몇 가지 명백한 걸림돌에 대한 간단한 요약입니다.

  • 사용 mod_rewrite.htaccess

    디렉토리 별 구성 파일에서 실제로 RewriteRules를 사용하려면 다음을 수행해야합니다.

    • 서버가 AllowOverride All활성화 되어 있는지 확인하십시오 . 그렇지 않으면 디렉토리 별 .htaccess지시문이 무시되고 RewriteRules가 작동하지 않습니다.

    • 분명히 했습니다 mod_rewrite활성화 당신의 httpd.conf모듈 섹션.

    • 각 규칙 목록 앞에 RewriteEngine On스틸을 붙 입니다. mod_rewrite가 암시 적으로 활성화되어 <VirtualHost>있고 <Directory>섹션에서는 디렉토리 별 .htaccess파일을 개별적으로 소환해야합니다.

  • 슬래시 ^/가 일치하지 않습니다

    일반적으로 .htaccessRewriteRule 패턴을 시작하지 않아야 ^/합니다.

     RewriteRule ^/article/\d+$  …
                  ↑
    

    이것은 종종 오래된 튜토리얼에서 볼 수 있습니다. 그리고 그것은 고대 아파치 1.x 버전에 맞았습니다. 요즘 요청 경로는 RewriteRules 에서 편리 하게 디렉토리에 상대적 입니다 .htaccess. 그냥 앞 /을 내버려 두십시오 .

    · 슬래시는 여전히 <VirtualHost>섹션 에서 정확 합니다. 그렇기 때문에 ^/?규칙 패리티에 대해 선택적으로 선택되는 경우가 종종 있습니다 .
    · 또는를 사용할 때도 RewriteCond %{REQUEST_URI}선두와 일치합니다 /.
    · Webmaster.SE 참고 : mod_rewrite 패턴에서 선행 슬래시 (/)는 언제 필요합니까?

  • <IfModule *> 래퍼가 시작되었습니다!

    많은 예에서 이것을 보았을 것입니다.

    <IfModule mod_rewrite.c>
       Rewrite… 
    </IfModule>
    
    • 그것은 수행 에서 메이크업 감각 <VirtualHost>섹션 -이 같은 ScriptAliasMatch 같은 다른 대체 옵션과 결합 된 경우. (그러나 아무도 그렇게하지 않습니다).
    • 또한 .htaccess오픈 소스 프로젝트가 많은 기본 규칙 세트에 일반적으로 배포됩니다 . 그것은 단지 폴백 (fallback)과 같은 의미이며 "추악한"URL을 기본값으로 유지합니다.

    그러나 일반적으로 자신의 파일 에는 원하지 않습니다.htaccess .

    • 첫째, mod_rewrite는 임의로 분리되지 않습니다. (그렇다면 더 큰 문제가 생길 것입니다).
    • 실제로 비활성화되어 있으면 RewriteRules가 여전히 작동하지 않습니다.
    • HTTP 500오류 를 방지하기위한 것 입니다. 일반적으로 달성하는 것은 HTTP 404오류로 사용자를 매기는 것입니다. ( 생각하면 훨씬 사용자 친화적이지 않습니다.)
    • 실제로 더 유용한 로그 항목이나 서버 알림 메일을 억제합니다. 당신은 없을 거라고 아무도 현명를 당신의 RewriteRules가 작동하지 않을 이유에.

    일반화 된 보호 수단으로 유혹되는 것들은 종종 실제로 장애물로 밝혀졌습니다.

  • RewriteBase필요 하지 않으면 사용 하지 마십시오

    많은 복사 + 붙여 넣기 예에는 RewriteBase /지시문이 포함되어 있습니다 . 어쨌든 암시 적 기본값이됩니다. 따라서 실제로는 필요하지 않습니다. 멋진 VirtualHost 다시 쓰기 체계에 대한 해결 방법이며 일부 공유 호스팅 업체의 DOCUMENT_ROOT 경로를 잘못 추측했습니다.

    더 깊은 하위 디렉토리의 개별 웹 응용 프로그램과 함께 사용하는 것이 좋습니다. 이러한 경우 RewriteRule 패턴을 단축 할 수 있습니다. 일반적으로 디렉토리 별 규칙 세트에서 상대 경로 지정자를 선호하는 것이 가장 좋습니다.

    .htaccess에서 RewriteBase의 작동 방식을 참조하십시오.

  • MultiViews가상 경로가 겹칠 때 비활성화

    URL 재 작성은 주로 가상 수신 경로 를 지원하는 데 사용됩니다 . 일반적으로 당신은 단지 하나의 디스패처 스크립트 (가 index.php) 또는 몇 개인 핸들러 ( articles.php, blog.php, wiki.php, ...). 후자 유사한 가상 RewriteRule 경로와 충돌 할 수 있습니다 .

    /article/123예를 들어 요청 article.php/123PATH_INFO로 암시 적으로 맵핑 될 수 있습니다 . commonplace RewriteCond !-f+로 규칙을 지키고 !-dPATH_INFO 지원을 비활성화하거나 disable으로 설정해야 Options -MultiViews합니다.

    어떤 당신이 항상 말을하지 해야합니다 . 컨텐츠 협상은 가상 자원에 대한 자동화입니다.

  • 주문이 중요하다

    mod_rewrite에 대해 알고 싶은 모든 것을 참조하십시오 . 여러 RewriteRules를 결합하면 종종 상호 작용이 발생합니다. 이것은 [L]플래그 당 습관적으로 방지 할 수있는 것이 아니라 한 번 정복 한 계획입니다. 가상 경로가 실제 대상 핸들러에 도달 할 때까지 한 규칙에서 다른 규칙으로 가상 경로를 다시 다시 작성할있습니다 .

    그럼에도 불구하고 당신은 것입니다 종종 가장 구체적인 규칙 (고정 문자열이 원하는 /forum/…패턴, 또는 더 제한적인 자리 [^/.]+에서) 초기 규칙을. 일반적인 말 괄호 규칙 ( .*)이 나중 규칙 에 더 잘 남습니다 . (예외는 RewriteCond -f/-d기본 블록으로서의 보호입니다.)

  • 스타일 시트 및 이미지 작동이 중지됩니다

    가상 디렉터리 구조를 도입하면 /blog/article/123HTML의 상대 리소스 참조 (예 :)에 영향을줍니다 <img src=mouse.png>. 다음으로 해결할 수 있습니다.

    • 서버 절대 참조 만 사용 href="https://stackoverflow.com/old.html"하거나src="/logo.png"
    • 종종 <base href="https://stackoverflow.com/index">HTML <head>섹션 에 추가하면 됩니다 . 이것은 이전에 있었던 것에 대한 상대적 참조를 암시 적으로 리 바인드합니다.

    .css또는 다른 RewriteRules .png를 만들어 원래 위치 로 리 바인드 하거나 경로를 지정할 수도 있습니다. 그러나 그것은 불필요하거나 여분의 리디렉션이 발생하고 캐싱을 방해합니다.

    참조 : CSS, JS와 이미지가 꽤 URL이 표시되지 않습니다

  • RewriteConds는 하나의 RewriteRule 만 마스크합니다.

    일반적인 오해는 RewriteCond가 여러 RewriteRules를 시각적으로 정렬하기 때문에 여러 개의 RewriteRules를 차단한다는 것입니다.

     RewriteCond %{SERVER_NAME} localhost
     RewriteRule ^secret  admin/tools.php
     RewriteRule ^hidden  sqladmin.cgi
    

    기본적으로 그렇지 않은 것. 당신은 그들을 사용하여 그들을 연결할 수 있습니다[S=2] 플래그. 그렇지 않으면 반복해야합니다. 재 작성 처리를 일찍 [END] 수행하기 위해 "반전 된"기본 규칙을 만들 수도 있습니다.

  • QUERY_STRING이 RewriteRules에서 면제

    RewriteRule index.php\?x=ymod_rewrite는 기본값 당 상대 경로와 비교하기 때문에을 일치시킬 수 없습니다 . 그러나 다음을 통해 별도로 일치시킬 수 있습니다.

     RewriteCond %{QUERY_STRING} \b(?:param)=([^&]+)(?:&|$)
     RewriteRule ^add/(.+)$  add/%1/$1  # ←──﹪₁──┘
    

    쿼리 문자열 변수를 mod_rewrite와 어떻게 일치시킬 수 있습니까?를 참조하십시오 .

  • .htaccess vs. <VirtualHost>

    디렉토리 별 구성 파일에서 RewriteRules를 사용하는 경우 정규 표현식 성능에 대한 걱정은 의미가 없습니다. Apache는 공통 라우팅 프레임 워크를 사용하여 PHP 프로세스보다 더 긴 컴파일 된 PCRE 패턴을 유지합니다. 트래픽이 많은 사이트의 경우 규칙 테스트가 완료되면 규칙 세트를 가상 호스트 서버 구성으로 이동하는 것을 고려해야합니다.

    이 경우 선택적 ^/?디렉토리 구분 기호 접두사를 선호하십시오 . 이를 통해 PerDir과 서버 구성 파일간에 RewriteRules를 자유롭게 이동할 수 있습니다.

  • 무언가 가 작동하지 않을 때마다

    걱정하지 마십시오.

    • 비교 access.logerror.log

      종종 RewriteRule이 error.logand 및 을보고 오작동하는 방식을 파악할 수 있습니다 access.log. 액세스 시간을 연관시켜 원래 요청 경로와 Apache가 해석 할 수없는 경로 / 파일을 확인하십시오 (오류 404/500).

      이것은 어느 RewriteRule이 범인인지는 알려주지 않습니다. 그러나 접근하기 어려운 최종 경로 /docroot/21-.itle?index.php는 추가 검사 장소를 제공 할 수 있습니다. 그렇지 않으면 예측 가능한 경로를 얻을 때까지 규칙을 비활성화하십시오.

    • RewriteLog 활성화

      Apache RewriteLog 문서를 참조하십시오 . 디버깅을 위해 vhost 섹션에서 활성화 할 수 있습니다.

      # Apache 2.2
      RewriteLogLevel 5
      RewriteLog /tmp/rewrite.log
      
      # Apache 2.4
      LogLevel alert rewrite:trace5
      #ErrorLog /tmp/rewrite.log
      

      그러면 각 요청에 따라 들어오는 요청 경로가 어떻게 수정되는지에 대한 자세한 요약이 제공됩니다.

      [..] applying pattern '^test_.*$' to uri 'index.php'
      [..] strip per-dir prefix: /srv/www/vhosts/hc-profi/index.php -> index.php
      [..] applying pattern '^index\.php$' to uri 'index.php'
      

      지나치게 일반적인 규칙과 정규식 사고를 좁히는 데 도움이됩니다.

      참조 :
      · .htaccess가 작동하지 않음 (mod_rewrite)
      · .htaccess 재 작성 규칙 디버깅 팁

    • 자신의 질문을하기 전에

      아시다시피, 스택 오버플로는 mod_rewrite에 대한 질문을하는 데 매우 적합합니다. 주제에 그들을 만들 사전 연구와 시도 (회피 중복 응답)을 포함하여, 기본 보여 이해 및 :

      • 입력 URL, 잘못 작성된 대상 경로, 실제 디렉토리 구조의 전체 예제를 포함하십시오 .
      • 전체 RewriteRule의 세트, 그러나 또한 추정 결함이 밖으로 하나.
      • $_SERVER매개 변수가 일치하지 않는 경우 Apache 및 PHP 버전, OS 유형, 파일 시스템, DOCUMENT_ROOT 및 PHP 환경.
      • 귀하의 발췌 access.logerror.log기존 규칙이 해결 된 사항을 확인합니다. 더 나은 아직 rewrite.log요약.

      이를 통해보다 빠르고 정확한 답변을 얻을 수 있으며 다른 사람들에게 더 유용합니다.

  • 당신의 코멘트 .htaccess

    어딘가에서 예제를 복사하는 경우을 포함하도록주의하십시오 # comment and origin link. 속성을 생략하는 것은 나쁜 방법 일 뿐이지 만 나중에 유지 관리에 실제로 피해를 주기도합니다. 모든 코드 또는 튜토리얼 소스를 문서화하십시오. 특히 미지의 동안에는 마법의 블랙 박스처럼 취급하지 않는 것에 더 관심을 가져야합니다.

  • "SEO"가 아닙니다. URL

    면책 조항 : 단지 애완 동물 친구. 종종 "SEO"링크 또는 무언가라는 URL 재 작성 체계가 들립니다. 이것은 인터넷 검색 예제에 유용하지만 날짜가 지난 잘못된 이름입니다.

    현대적인 검색 엔진의 아무도는 정말 방해하지 않습니다 .html.php패스 세그먼트 (segment), 또는에서 ?id=123그 문제에 대한 쿼리 문자열. AltaVista와 같은 오래된 검색 엔진은 잠재적으로 모호한 액세스 경로를 가진 웹 사이트를 크롤링 하지 않았습니다 . 최신 크롤러는 종종 깊은 웹 리소스를 원합니다.

    개념적으로 "예쁜"URL을 사용해야하는 것은 웹 사이트를 사용자에게 친숙 하게 만드는 것 입니다.

    1. 읽기 쉽고 명백한 리소스 체계가 있습니다.
    2. URL의 수명이 길다 (AKA permalinks ).
    3. 를 통해 검색 가능성 제공 /common/tree/nesting.

    그러나 적합성에 대한 고유 한 요구 사항을 희생하지 마십시오.

도구

대부분의 GET 매개 변수 URL에 대해 RewriteRules를 생성하는 다양한 온라인 도구가 있습니다.

대부분 [^/]+일반 자리 표시자를 출력 하지만 사소한 사이트에는 충분합니다.


여전히 약간의 재 작성, 더 많은 링크가 필요하며 많은 부제목이 다소 불쾌합니다. 여기에 다른 답변과 겹치는 부분이 있으므로 아마도 줄일 수 있습니다. 그것은 주로 시각적 예와 일반적인 문제 목록에 관한 것입니다.
mario

3
오랫동안 대답의 아름다움을 보지 못했습니다! 읽는 동안 눈이 빛납니다. 그런 답변을 게시 중지하지 마십시오 :)
Rizier123

1
훌륭한 게시물. mod_rewrite의 기본 개념을 매우 빠르게 이해할 수있었습니다.
breez

6

mod_rewrite의 대안

RewriteRules를 사용하지 않고도 많은 기본 가상 URL 체계를 달성 할 수 있습니다. Apache는 PHP 스크립트를 .php확장 없이 그리고 가상 PATH_INFO인수 로 호출 할 수 있도록 합니다.

  1. 사용 PATH_INFO , 루크

    요즘 AcceptPathInfo On은 종종 기본적으로 활성화되어 있습니다. 기본적으로 .php다른 리소스 URL이 가상 인수를 수행하도록 허용 합니다.

    http://example.com/script.php/virtual/path
    

    이제 이것은 추가 인수를 원하는 /virtual/path대로 $_SERVER["PATH_INFO"]처리 할 수있는 곳 으로 PHP에 표시됩니다 .

    이것에 아파치 별도의 입력 경로 세그먼트를 구비 한 편리하지 $1, $2, $3별개로 전달 $_GETPHP하는 변수. 적은 노력으로 "예쁜 URL"을 모방 할뿐입니다.

  2. 확장 을 숨기려면 MultiViews 활성화.php

    .phpURL에서 "파일 확장자"를 피하는 가장 간단한 옵션 은 다음과 같습니다.

    Options +MultiViews
    

    일치하는 기본 이름으로 인해 Apache에서 article.phpHTTP 요청을 선택 합니다 /article. 그리고 이것은 위에서 언급 한 PATH_INFO 기능과 함께 잘 작동합니다. 그래서 당신은 같은 URL을 사용할 수 있습니다 http://example.com/article/virtual/title. 여러 PHP 호출 지점 / 스크립트가있는 전통적인 웹 응용 프로그램이있는 경우 의미가 있습니다.

    MultiViews는 다른 / 광범위한 목적을 가지고 있습니다. 그것은 초래 아주 작은 아파치가 항상 일치하는 basename이 다른 파일을 찾습니다 있기 때문에, 성능 저하. 그것은 실제로 의미있어 내용 협상 브라우저 (예 : 가용 자원 중 가장 좋은 대안을받을 수 있도록, article.en.php, article.fr.php, article.jp.mp4).

  3. 확장없는 .php스크립트를 위한 SetType 또는 SetHandler

    .phpURL에서 접미사 를 피하는보다 직접적인 접근 방식 은 다른 파일 체계에 맞게 PHP 처리기구성하는 것 입니다. 가장 간단한 옵션은 .htaccess다음을 통해 기본 MIME / 핸들러 유형을 재정의하는 것입니다 .

    DefaultType application/x-httpd-php
    

    이렇게하면 article.php스크립트 이름 을 article(확장자없이) 그냥 바꿀 수 있지만 여전히 PHP 스크립트로 처리 할 수 ​​있습니다.

    이제 모든 확장 파일이 PHP를 통해 파이프되기 때문에 보안 및 성능에 영향을 줄 수 있습니다. 따라서 개별 파일에 대해서만이 동작을 설정할 수 있습니다.

    <Files article>
      SetHandler application/x-httpd-php
      # or SetType 
    </Files>
    

    이것은 서버 설정과 사용 된 PHP SAPI에 따라 다소 다릅니다. 일반적인 대안은 ForceType application/x-httpd-php또는 AddHandler php5-script입니다.

    이러한 설정은 하나 .htaccess에서 하위 폴더로 전파됩니다 . 당신은 항상 스크립트 실행 (사용하지 않아야 SetHandler None하고 Options -Exec또는 php_flag engine off정적 자원 등), 업로드 / 디렉토리 등

  4. 다른 Apache 재 작성 체계

    많은 옵션 중에서 Apache는 RewriteRules mod_alias와 마찬가지로 작동하는 기능을 제공 합니다 mod_rewrite. <VirtualHost>그러나 이들 대부분은 디렉토리 별 .htaccess구성 파일이 아닌 섹션 에서 설정해야 합니다.

    • ScriptAliasMatch주로 CGI 스크립트 용이지만 PHP에서도 작동합니다. 그것은 어떤 식 으로든 정규 표현식을 허용합니다 RewriteRule. 실제로 모든 전면 컨트롤러를 구성하는 것이 가장 강력한 옵션 일 것입니다.

    • 그리고 평범한 Alias몇 가지 간단한 다시 쓰기 체계도 도움이됩니다.

    • ErrorDocumentPHP 스크립트가 가상 경로를 처리하도록 일반 지시문도 사용할 수 있습니다. 그러나 이것은 해결하기 어려운 해결책이지만 GET 요청 이외의 것은 금지하고 error.log를 정의에 따라 넘칩니다.

    추가 팁 은 http://httpd.apache.org/docs/2.2/urlmapping.html 을 참조 하십시오 .

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