Điểm:1

.htaccess mod_rewrite không bắt được tất cả RewriteRules

lá cờ de

Có một ứng dụng PHP với bộ định tuyến PHP làm điểm vào cho tất cả các yêu cầu được đặt bên trong index.php. Tôi đang cố viết một tệp .htaccess để chuyển tiếp mọi yêu cầu tới index.php ngoại trừ các yêu cầu API và tài nguyên thiết kế. Vì vậy, tôi đang cố gắng để có được hành vi sau:

  1. ví dụ.com/api/v1/* nên phục vụ api_v1.php
  2. example.com/any_path/resource.css => nên phục vụ tài nguyên.css nếu nó tồn tại (có nhiều tiện ích mở rộng được phép; .css chỉ là một ví dụ)
  3. phục vụ index.php cho bất cứ điều gì không thuộc các điều kiện trên

Cho rằng .htaccess được đánh giá từ trên xuống dưới, từ điều kiện cụ thể đến điều kiện chung và cờ đó [L] sẽ phá vỡ việc thực thi nếu bất cứ điều gì phù hợp, tôi đã xoay sở để đưa ra những điều sau đây .htaccess:

Viết LạiEngine Trên

# Ngăn chặn chuyển hướng 301 bằng dấu gạch chéo khi thư mục tồn tại và không có dấu gạch chéo được thêm vào
# Đây không phải là vấn đề bảo mật ở đây vì bộ định tuyến PHP được sử dụng và tất cả các đường dẫn đều được chuyển hướng
Thư mụcSlash Off

#1. Viết lại cho url API
RewriteRule ^api/v1/(.*)$ api_v1.php [L,NC]

#2. Viết lại vào index.php ngoại trừ các tệp thiết kế/tài liệu/favicon/robots tồn tại
RewriteCond %{REQUEST_URI} !.(css|js|png|jpg|jpeg|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$
RewriteCond %{REQUEST_URI} !^(robots\.txt|favicon\.ico)$ [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L]

#3. Viết lại mọi thứ khác
RewriteRule ^(.*)$ index.php [L]

Sử dụng đoạn mã trên, có vẻ như việc truy cập ví dụ.com/api/v1/ không thực hiện api_v1.php. Thay vào đó, nó sẽ tiếp tục và thực hiện index.php

ví dụ.com/api/v1/ sẽ chỉ hoạt động nếu tôi xóa tất cả các điều kiện sau dòng 8.

Tôi làm gì sai ở đây?

lá cờ kz
Có một chút không rõ ràng chính xác những gì bạn đang cố gắng làm.Có nên viết lại một số yêu cầu nhất định thành `index.php` ngay cả khi chúng tồn tại dưới dạng tệp vật lý chứ không phải một trong các loại tệp đã nêu? Các yêu cầu về tài nguyên (`.css`, `.jpg`, v.v.) có nên vẫn được viết lại thành `index.php` nếu chúng không tồn tại? (tức là bạn có các URL hợp pháp có "phần mở rộng tệp" như thế này không?)
caffeine avatar
lá cờ de
@MrWhite Có, nếu không tìm thấy tệp .css, hãy viết lại thành index.php để tôi có thể xử lý đúng lỗi 404 từ index.php. Nếu tệp .css tồn tại, hãy phục vụ nó, nếu không hãy viết lại vào index.php
lá cờ kz
Nhưng còn những loại tệp bạn chưa nêu rõ ràng thì sao? Chúng có nên được định tuyến thông qua `index.php` bất kể chúng có tồn tại hay không? (Bạn có cần nêu rõ danh sách các loại tệp đã biết không?)
caffeine avatar
lá cờ de
Vâng, bất cứ điều gì KHÔNG có trong danh sách đó, cho dù nó có tồn tại hay không, nó nên được viết lại thành index.php. Điều phức tạp duy nhất ở đây là tôi cũng viết lại thành index.php cho các tên tệp có trong danh sách nhưng KHÔNG tồn tại trên máy chủ. Về cơ bản, tôi cố gắng phân phối trực tiếp các tệp .css nếu chúng tồn tại, nếu không thì viết lại mọi thứ thành index.php (tham khảo điều kiện #2 và #3)
lá cờ kz
Tôi đã cập nhật câu trả lời của mình bằng một giải pháp hoàn chỉnh dựa trên nhận xét của bạn.
Điểm:1
lá cờ kz

có vẻ như việc truy cập site.com/api/v1/ không thực thi api_v1.php. Thay vào đó, nó sẽ tiếp tục và thực thi index.php

Có, bởi vì quy tắc đầu tiên viết lại yêu cầu thành api_v1.php và điều này cuối cùng được viết lại thành index.php theo quy tắc thứ hai (vì php không có trong danh sách các tiện ích mở rộng bị loại trừ trong lần đầu tiên điều kiện, tình trạng, trạng thái, điều kiện thứ hai cũng thành công nên điều kiện thứ ba không được xử lý - xem bên dưới) trong lần chuyển thứ hai của công cụ viết lại. trong một danh mục bối cảnh (tức là .htaccess) các l cờ không dừng tất cả quá trình xử lý, nó chỉ dừng dòng điện đi qua công cụ viết lại. Công cụ viết lại lặp lại cho đến khi URL đi qua không thay đổi.

Bạn có thể giải quyết vấn đề này trên Apache 2.4 bằng cách sử dụng CHẤM DỨT cờ, thay vì l, theo quy tắc đầu tiên để dừng tất cả quá trình xử lý bằng công cụ viết lại.

Ví dụ:

RewriteRule ^api/v1/ api_v1.php [NC,END]

(Tôi đã xóa dấu (.*)$ trên biểu thức chính quy vì nó không cần thiết ở đây và làm cho biểu thức chính quy kém hiệu quả hơn một chút.)

Tuy nhiên, thực tế là một yêu cầu cho một hiện có .php tệp được viết lại bởi các quy tắc sau này của bạn thực sự chứng minh rằng các quy tắc thứ hai và thứ ba của bạn dường như không hoạt động như dự định...

#2. Viết lại vào index.php ngoại trừ các tệp thiết kế/tài liệu/favicon/robots tồn tại
RewriteCond %{REQUEST_URI} !.(css|js|png|jpg|jpeg|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$
RewriteCond %{REQUEST_URI} !^(robots\.txt|favicon\.ico)$ [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L]

#3. Viết lại mọi thứ khác
RewriteRule ^(.*)$ index.php [L]

Nếu bạn yêu cầu một cái gì đó.php sau đó là người đầu tiên điều kiện, tình trạng, trạng thái thành công (vì .phpkhông phải đưa vào danh sách). Điều kiện thứ hai cũng thành công (không phải robot.txt hoặc favicon.ico). Vì điều kiện thứ hai rõ ràng HOẶC với điều kiện thứ ba nên điều kiện thứ ba không được xử lý.Tất cả các điều kiện đều thành công và yêu cầu được viết lại thành index.php (bất kể một cái gì đó.php tồn tại hay không).

Mặt khác, nếu bạn yêu cầu tài nguyên.css sau đó là người đầu tiên điều kiện, tình trạng, trạng thái thất bại (vì nó có một .css sự mở rộng). Vì điều kiện này hoàn toàn là AND'd nên không có điều kiện nào khác được xử lý và quy tắc không được kích hoạt. Quy tắc thứ ba sau đó viết lại vô điều kiện tài nguyên.css đến index.php, bất kể nó có tồn tại hay không!

Vì vậy, điều này không kiểm tra xem tài nguyên được yêu cầu (css, jpg, v.v.) "tồn tại" như được ngụ ý bởi nhận xét trước đó. Điều kiện thứ ba (kiểm tra yêu cầu không ánh xạ tới tệp) chỉ được xử lý khi điều kiện OR trước đó không thành công VÀ điều kiện đầu tiên thành công. Nói cách khác, điều kiện thứ 3 chỉ được xử lý khi bạn yêu cầu /robots.txt - mà tôi chắc chắn không phải là ý định của bạn.

Nói cách khác, các quy tắc #2 và #3 (bất chấp sự phức tạp rõ ràng của chúng) dường như được viết lại khá nhiều. mọi thứ đến index.php.

Giải pháp hoàn chỉnh

Dựa trên nhận xét bổ sung của bạn:

  • Đối với một tập hợp con các loại tệp, hãy cung cấp tài nguyên - nếu nó tồn tại. Nếu tài nguyên không tồn tại thì hãy gửi yêu cầu tới index.php.

  • Đối với các loại tệp khác, hãy gửi yêu cầu tới index.php, bất kể tài nguyên đó có tồn tại hay không.

  • Một vài yêu cầu (tức là. /robots.txt/favicon.ico) không được gửi đến index.php.

Thay vào đó, hãy thử những cách sau:

# Ngăn chặn chuyển hướng 301 bằng dấu gạch chéo khi thư mục tồn tại và không có dấu gạch chéo được thêm vào
# Đây không phải là vấn đề bảo mật ở đây vì bộ định tuyến PHP được sử dụng và tất cả các đường dẫn đều được chuyển hướng
Thư mụcSlash Off

# Vì "DirectorySlash Off" được đặt, hãy đảm bảo rằng danh sách thư mục mod_auotindex bị tắt
Tùy chọn -Chỉ mục

Viết LạiEngine Trên

#1. Viết lại cho url API
RewriteRule ^api/v1/ api_v1.php [NC,END]

#2. Các URL/tệp đã biết được phục vụ trực tiếp
RewriteRule ^(index\.php|robots\.txt|favicon\.ico)$ - [END]

#3.Một số loại tệp (tài nguyên) được cung cấp trực tiếp nếu chúng tồn tại
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule \.(css|js|png|jpe?g|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$ - [END]

#4. Viết lại mọi thứ khác
RewriteRule ^ index.php [KẾT THÚC]

Các quy tắc kết thúc sớm cho mọi thứ cần được phục vụ trực tiếp, vì vậy chúng tôi chỉ cần viết lại thành index.php một lần trong quy tắc cuối cùng.

Lưu ý rằng tôi đã bao gồm index.php trong quy tắc #2. Đây là một sự tối ưu hóa, mặc dù không thực sự cần thiết nếu sử dụng CHẤM DỨT cờ (trái ngược với l) trên quy tắc cuối cùng.

Theo tùy chọn, bạn có thể chọn chuyển hướng bất kỳ thẳng thắn yêu cầu index.php quay lại thư mục gốc (để chuẩn hóa URL cho các công cụ tìm kiếm). Đây chỉ là trong trường hợp /index.php được hiển thị (hoặc đoán) cho người dùng cuối.

Ví dụ: thêm phần sau vào sau quy tắc đầu tiên cho API:

#1.5 Chuyển hướng các yêu cầu trực tiếp tới "/index.php" trở lại "/" (gốc)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php$ / [R=301,L]

Các điều kiện, tình trạng, trạng thái kiểm tra chống lại REDIRECT_STATUS biến môi trường là cần thiết để ngăn vòng lặp chuyển hướng - để tránh chuyển hướng URL đã viết lại. (Mặc dù, một lần nữa, điều này không bắt buộc nếu sử dụng CHẤM DỨT gắn cờ trên quy tắc cuối cùng/viết lại.)

caffeine avatar
lá cờ de
Cảm ơn những lời giải thích rộng rãi. Điều này chắc chắn đã giải quyết được sự cố của tôi và mang lại một số thông tin rất hữu ích về chủ đề này.
Điểm:0
lá cờ ng

Cố gắng đặt một điều kiện viết lại trước mỗi quy tắc và sau đó phá vỡ quy tắc. Nói cách khác, mọi điều kiện cần phải có quy tắc riêng.

điều kiện -> quy tắc
điều kiện -> quy tắc
...

Đăng câu trả lời

Hầu hết mọi người không hiểu rằng việc đặt nhiều câu hỏi sẽ mở ra cơ hội học hỏi và cải thiện mối quan hệ giữa các cá nhân. Ví dụ, trong các nghiên cứu của Alison, mặc dù mọi người có thể nhớ chính xác có bao nhiêu câu hỏi đã được đặt ra trong các cuộc trò chuyện của họ, nhưng họ không trực giác nhận ra mối liên hệ giữa câu hỏi và sự yêu thích. Qua bốn nghiên cứu, trong đó những người tham gia tự tham gia vào các cuộc trò chuyện hoặc đọc bản ghi lại các cuộc trò chuyện của người khác, mọi người có xu hướng không nhận ra rằng việc đặt câu hỏi sẽ ảnh hưởng—hoặc đã ảnh hưởng—mức độ thân thiện giữa những người đối thoại.