Bài 1

nginx chọn khối location thế nào

Một request tới, nhiều khối location cùng khớp. nginx không chọn khối viết đầu tiên, cũng không chọn khối cụ thể nhất. Nó chạy năm bước cố định, và thứ tự của năm bước đó quyết định khối nào thắng.

Năm bước, đúng thứ tự

  1. Có khối = /đường-dẫn khớp chính xác không? Có thì thắng ngay, dừng luôn.
  2. Tìm khối tiền tố khớp dài nhất — tính cả khối mang ^~. Ghi nhớ lại, chưa dùng vội.
  3. Khối dài nhất vừa tìm có mang ^~ không? Có thì dùng nó và bỏ qua toàn bộ regex.
  4. Thử các regex theo thứ tự viết trong file. Cái đầu tiên khớp thì thắng.
  5. Không regex nào khớp thì quay lại dùng khối tiền tố đã ghi nhớ ở bước 2.
Bước 4 xét regex theo thứ tự viết, không theo độ cụ thể Một regex hẹp hơn nhưng viết sau một regex rộng hơn sẽ không bao giờ chạy. Cấu hình đo bên dưới có đúng trường hợp đó: khối 4 không thắng ở bất kỳ đường dẫn nào trong 14 đường dẫn đã thử, và nginx vẫn khởi động bình thường, không phát ra cảnh báo nào.

Đo trên nginx thật

Cấu hình dưới đây nạp vào container nginx:1.27-alpine, mỗi khối trả về tên của chính nó, rồi gọi curl lần lượt 14 đường dẫn.

location = /exact          { return 200 "1 exact"; }
location ^~ /images/       { return 200 "2 prefix-uu-tien"; }
location ~ \.(gif|jpg)$    { return 200 "3 regex-gif-jpg"; }
location ~ ^/img/.*\.gif$  { return 200 "4 regex-img-gif"; }
location ~* \.PNG$         { return 200 "5 regex-png-ci"; }
location /img/             { return 200 "6 prefix-img"; }
location /doc              { return 200 "7 prefix-doc"; }
location /document         { return 200 "8 prefix-document"; }
location /                 { return 200 "9 mac-dinh"; }
Đường dẫnKhối thắngVì sao
/exact1 exactkhớp chính xác, bước 1
/exact/9 mac-dinhkhớp chính xác là khớp từng ký tự; thêm một dấu / là URI khác
/images/a.gif2 prefix-uu-tien^~ chặn regex ở bước 3, dù khối 3 cũng khớp
/images/b.txt2 prefix-uu-tiencùng khối, ở đây không regex nào khớp nên kết quả trùng nhau
/img/a.gif3 regex-gif-jpgregex viết trước thắng; khối 4 cụ thể hơn nhưng không bao giờ chạy
/img/a.GIF6 prefix-imgcả khối 3 và 4 đều dùng ~ phân biệt hoa thường, không khớp .GIF, nên rơi về bước 5
/img/b.txt6 prefix-imgkhông regex nào khớp nên quay lại tiền tố, bước 5
/photo.gif3 regex-gif-jpgregex khớp
/photo.PNG5 regex-png-ci~* không phân biệt hoa thường
/photo.png5 regex-png-cikhối 3 chỉ có gif và jpg
/doc7 prefix-doctiền tố khớp
/document8 prefix-documenttiền tố dài hơn thắng
/documentation8 prefix-documentvẫn là tiền tố dài nhất
/khac9 mac-dinhchỉ còn /
Một lỗi gặp ngay khi dựng bộ đo này Bản cấu hình đầu tiên có cả location ^~ /images/ lẫn location /images/. nginx từ chối khởi động: [emerg] duplicate location "/images/". Modifier không tạo ra khối riêng — ^~ /x/ và /x/ là cùng một location. Phòng thí nghiệm bên dưới tái hiện đúng lỗi này nếu bạn viết cả hai.

Phòng thí nghiệm

Sửa cấu hình và đường dẫn tuỳ ý. Thuật toán chạy ngay trên trình duyệt là bản viết lại năm bước ở trên, và nó đã được đối chiếu với nginx 1.27.5 thật trên đúng 14 đường dẫn trong bảng — khớp 14/14.

Các khối location

Đường dẫn cần thử

nginx xét theo thứ tự này

    Ba chỗ hay hỏng

    Tự kiểm tra

    Có location /api/ và location ~ \.json$. Request /api/data.json vào khối nào? Vào khối regex. Tiền tố /api/ được ghi nhớ ở bước 2 nhưng không mang ^~, nên bước 4 vẫn chạy và regex khớp. Muốn tiền tố thắng thì đổi thành location ^~ /api/.
    Vì sao /img/b.txt vào khối tiền tố còn /img/a.gif vào khối regex? Cả hai đều có tiền tố dài nhất là /img/, nhưng bước 4 chạy trước bước 5. Với .txt không regex nào khớp nên mới quay lại tiền tố; với .gif thì regex khớp và thắng luôn.
    Cùng cấu hình đó, /img/a.GIF vào khối nào? Khối 6, tiền tố /img/. Khối 3 và khối 4 đều dùng ~ nên phân biệt hoa thường và không khớp phần mở rộng viết hoa; chỉ khối 5 dùng ~*, nhưng nó tìm .PNG. Đây là số đo thật, không phải suy luận.
    Thêm location ^~ /img/ vào cấu hình trong bảng thì chuyện gì xảy ra? nginx không khởi động: đã có location /img/, và modifier không tạo khối riêng nên đây là trùng location. Thử ngay trong phòng thí nghiệm phía trên.