יצירת תמיכה ב path info ל nginx

שרת nginx הוא שרת HTTP קל ומהיר אשר מספק תמיכה לכל תקשורת הקשורה ל HTTP כולל תמיכה ב Proxy ו Reversed Proxy. השרת אבל לא תומך ב CGI בכלל, אלא אם מתחכמים לו ומגדירים FAST CGI שמשמש משהו בסגנון reversed proxy בשרת זה, אך הוא טיפה יותר מזה, היות והשרת יודע שזה FAST CGI ולא proxy רגיל, העניין הוא ששרת ה FAST CGI צריך לרוץ בפני עצמו ולא כתהליך בן של nginx בניגוד לאפצ'י,  lighttpd ועוד כמה שרתים שאני מכיר (חלקם תכנותיים בכלל).

השרת מאפשר לנו ליצור הרבה משתנים שיכולים להכיל הרבה מידע שיעזור לנו להגדיר דברים כמו שאנחנו רוצים.

יש מושג כזה ב HTTP שמוגר כ PATH_INFO, אבל זהו בעצם סוג של hack שדורש תמיכה בצד השרת ובצד ה CGI ביחד, היות ואנחנו מתלבשים על שם קובץ/ספרייה שאנחנו מבקשים אבל בעצם אנחנו מבקשים משהו שהוא לא קיים, ולכן תסריט CGI חייב לפענח את המידע הזה, ולא השרת.

בשביל להסביר מה זה PATH_INFO, פשוט תסתכלו על הכתובת של הפוסט הזה, ותראו שהוא עובד באמצעות השיטה הזו.

לצערי, לקח לי הרבה זמן למצוא נוסחה הגיונית שתעבוד בצד nginx עבור path_info, היות והוא אינו תומך בהם בברירת מחדל בכלל, אבל ממש כמו ב Apache יש חוקי rewrite שצריך לממש. אבל הבעיה שאני הגעתי אליה היתה שהוא משום מה משכפל את השכתוב שלי לנתיב הפיזי לפחות ל5 רמות פנימה, למרות שזה לא מה שהשכתוב ביקש לבצע (אולי באג).

בסוף הגעתי לנוסחה שעובדת לי, ואני אשים אותה כאן בתור תעוד לעוד אנשים הנתקלים בבעיות.
קובץ nginx.conf:

server {
 listen 80;
 server_name 127.0.0.1 ;
 root /path/to/the/site;
 index     main.php; # my "index" file is main.php

 set $path_info  ""; # creating a variable named $path_info
 set $script     $uri; # creating a variable named $script

 location / { # for normal location
   if (!-e $request_filename) { # no file name ?
      rewrite ^/(([a-z][a-z])/.*?)$ /main.php/$1 last; # of /2 letters/more = /main.php/the/found/path/info
   } # if
  } # location /

 location /main.php { # request of /main.php
   set $script     "main.php"; # set by hand the script name
   if ($uri ~ "^(main\.php)(/.*+)$") { # making path_info only if needed -> everything after main.php is a path info for us
     set $path_info  $2; # store the path_info to a variable
   }

   # some fastcgi settings
   fastcgi_pass   localhost:9000;
   fastcgi_param  SCRIPT_FILENAME
   $document_root$fastcgi_script_name;
   include        fastcgi_params; # environment variables for the fastcgi
 } # location
} # server

קובץ fastcgi_params:

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;
# decoding the url and setting a patg info environment variable
fastcgi_param  PATH_INFO          urldecode($path_info);
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;

fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;

fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;

fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

ויש לנו תמיכה ב path_info לפי כלל מסויים (כמובן שאפשר לעשות אותו יותר גנרי מזה, אבל אצלי התאמתי למבנה ספציפי).

אני מקווה שזה יעזור לכם במידה ויש לכם צורך ולא מצאתם איך לעשות את זה כמו שצריך (בנוסף למה שארתיום כתב).

3 מחשבות על “יצירת תמיכה ב path info ל nginx

  1. ארתיום

    לכל האנשים שקוראים את הפוסט הזה, תשימו אותו כסימניה… כי אני בזבזתי המון זמן עד שקלטתי כיצד לגרום ל־path_info לעבוד. אתה יכול לראות גם תסריט שנקרא cppcms_run‎‏ שכתבתי כדי לגרום ל־3 שרתים לעבוד עם fcgi.

    מעניין עכשיו ראיתי כיצד אתה מגדיר path_info… וקראתי מחדש את הספציפיקציות של CGI (ראה rfc3875) ואני לא מגדיר אותו נכון לא בתסריט שלו ולא בשרת http הפנימי של cppcms… צריך לתקן.

    הערה קטנה נוספת: lighttpd הוא לא מריץ מודולים כמו apache הוא שרת עם חוט יחיד שעושה "מיקור־חוץ" לכל העבודה האמתית. בפרט הרצת תסריטי fastcgi… למעשה אין דרך לעבוד עם lighttpd (וגם nginx) אלא דרך fastcgi או scgi.

    הדבר הכי מעצבן ב־nginx בנוסף להכל: הוא לא מעלה ומנהל תהליכים כמו lighttpd ובכלל די עצלן לכל מה שקשור לניהול. התיעוד שלו על הפנים… מצד שני, lighty זולג ויש לו בעיות אחרות.

    אגב… אתה מוזן להוסיף תיקון לדיון ב־whatsup.

  2. ik_5 מאת

    אני גם שרפתי הרבה מאוד זמן (יום שלם) על לגרום לזה לעבוד. מצאתי הרבה תעוד צד שלישי, אבל זה פשוט לא עבד אצלי, ואחרי הפסקה של כמה שעות אתמול, חזרתי ב11 בלילה לעבוד על זה וב2 הצלחתי לגרום לזה לעבוד.

    אני מוסיף קישור לזה ב whatsup.

להשאיר תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s