У меня есть сценарий Perl, который не работает, и я не знаю, как начать сужать проблему. Что я могу сделать?
Примечание: я добавляю вопрос, потому что действительно хочу добавить свой очень длинный ответ в Stackoverflow. Я продолжаю ссылаться на него в других ответах, и он заслуживает того, чтобы быть здесь. Не стесняйтесь редактировать мой ответ, если вам есть что добавить.
Ответы:
Этот ответ предназначен в качестве общей основы для решения проблем со сценариями Perl CGI и первоначально появился на Perlmonks как Troubleshooting Perl CGI Scripts . Это не полное руководство по каждой проблеме, с которой вы можете столкнуться, и не руководство по устранению ошибок. Это просто кульминация моего опыта отладки скриптов CGI в течение двадцати (с лишним!) Лет. Похоже, на этой странице было много разных домов, и я, кажется, забыл о ее существовании, поэтому добавляю ее в StackOverflow. Вы можете присылать мне любые комментарии или предложения по адресу bdfoy@cpan.org. Это также вики сообщества, но не стоит слишком нервничать. :)
Используете ли вы встроенные функции Perl для поиска проблем?
Включите предупреждения, чтобы Perl предупреждал вас о сомнительных частях вашего кода. Вы можете сделать это из командной строки с помощью
-w
переключателя, поэтому вам не нужно менять какой-либо код или добавлять прагму в каждый файл:Однако вы должны заставить себя всегда прояснять сомнительный код, добавляя
warnings
прагму ко всем своим файлам:Если вам нужно больше информации, чем короткое предупреждающее сообщение, используйте
diagnostics
прагму для получения дополнительной информации или посмотрите документацию perldiag :Вы сначала вывели действительный заголовок CGI?
Сервер ожидает, что первым выводом сценария CGI будет заголовок CGI. Как правило , это может быть так просто , как
print "Content-type: text/plain\n\n";
и с CGI.pm и его производных,print header()
. Некоторые серверы чувствительны к тому, что вывод ошибок (включенSTDERR
) отображается перед стандартным выводом (включенSTDOUT
).Попробуйте отправить ошибки в браузер
Добавить эту строку
к вашему сценарию. Это также отправляет ошибки компиляции в окно браузера. Обязательно удалите это перед переходом в производственную среду, так как дополнительная информация может представлять угрозу безопасности.
Что написано в журнале ошибок?
Серверы ведут журналы ошибок (по крайней мере, должны). Там должны появиться сообщения об ошибках с сервера и вашего скрипта. Найдите журнал ошибок и посмотрите, что в нем написано. Стандартного места для файлов журналов нет. Посмотрите в конфигурации сервера их местонахождение или спросите администратора сервера. Вы также можете использовать такие инструменты, как CGI :: Carp, чтобы хранить свои собственные файлы журналов.
Какие разрешения у скрипта?
Если вы видите такие ошибки, как «Разрешение отказано» или «Метод не реализован», это, вероятно, означает, что ваш скрипт недоступен для чтения и выполнения пользователем веб-сервера. На разновидностях Unix, изменить режим 755 рекомендуется:
chmod 755 filename
. Никогда не устанавливайте режим на 777!Вы пользуетесь
use strict
?Помните, что Perl автоматически создает переменные, когда вы их впервые используете. Это функция, но иногда она может вызывать ошибки, если вы неправильно введете имя переменной. Прагма
use strict
поможет вам найти такого рода ошибки. Это раздражает, пока вы к этому не привыкнете, но через некоторое время ваше программирование значительно улучшится, и вы сможете свободно совершать разные ошибки.Компилируется ли сценарий?
Вы можете проверить наличие ошибок компиляции с помощью
-c
переключателя. Сосредоточьтесь на первых обнаруженных ошибках. Промыть, повторить. Если вы получаете действительно странные ошибки, убедитесь, что в вашем скрипте есть правильные окончания строк. Если вы используете FTP в двоичном режиме, проверяете из CVS или что-то еще, что не обрабатывает перевод конца строки, веб-сервер может увидеть ваш сценарий как одну большую строку. Перенести скрипты Perl в режим ASCII.Сценарий жалуется на небезопасные зависимости?
Если ваш скрипт жалуется на небезопасные зависимости, вы, вероятно, используете
-T
переключатель для включения режима заражения, что хорошо, поскольку оно позволяет вам передавать непроверенные данные в оболочку. Если он жалуется, значит, он помогает нам писать более безопасные скрипты. Любые данные, поступающие извне программы (т. Е. Из среды), считаются испорченными. Особенно неприятны такие переменные среды, какPATH
иLD_LIBRARY_PATH
. Вы должны установить для них безопасное значение или полностью отключить их, как я рекомендую. В любом случае вы должны использовать абсолютные пути. Если при проверке на заражение возникает какая-то проблема, убедитесь, что вы не испортили данные. См. Подробности на странице руководства perlsec .Что происходит, когда вы запускаете его из командной строки?
Выводит ли сценарий то, что вы ожидаете, при запуске из командной строки? Сначала выводится заголовок, а за ним - пустая строка? Помните, что это
STDERR
может быть объединено,STDOUT
если вы находитесь на терминале (например, в интерактивном сеансе), и из-за буферизации может отображаться в беспорядочном порядке. Включите функцию автозапуска Perl, установив$|
значение true. Обычно вы можете видеть это$|++;
в программах CGI. После установки каждая печать и запись немедленно отправляется на вывод, а не буферизуется. Вы должны установить это для каждого дескриптора файла. Используйтеselect
для изменения дескриптора файла по умолчанию, например:В любом случае первым выводом должен быть заголовок CGI, за которым следует пустая строка.
Что произойдет, если вы запустите его из командной строки в среде, подобной CGI?
Среда веб-сервера обычно намного более ограничена, чем среда командной строки, и содержит дополнительную информацию о запросе. Если ваш сценарий отлично работает из командной строки, вы можете попробовать имитировать среду веб-сервера. Если проблема появляется, у вас проблема с окружающей средой.
Отключить или удалить эти переменные
PATH
LD_LIBRARY_PATH
ORACLE_*
переменныеУстановите эти переменные
REQUEST_METHOD
(установленоGET
,HEAD
илиPOST
в зависимости от обстоятельств)SERVER_PORT
(обычно устанавливается на 80)REMOTE_USER
(если вы делаете вещи с защищенным доступом)Последние версии
CGI.pm
(> 2.75) требуют, чтобы-debug
флаг получил старое (полезное) поведение, поэтому вам, возможно, придется добавить его в свойCGI.pm
импорт.Вы используете
die()
илиwarn
?Эти функции печатаются,
STDERR
если вы их не переопределили. Они также не выводят заголовок CGI. Вы можете получить ту же функциональность с такими пакетами, как CGI :: CarpЧто происходит после очистки кеша браузера?
Если вы считаете, что ваш скрипт делает правильные вещи, и когда вы выполняете запрос вручную, вы получаете правильный результат, возможно, виноват браузер. Очистите кеш и установите его размер равным нулю во время тестирования. Помните, что некоторые браузеры действительно глупы и на самом деле не будут перезагружать новый контент, даже если вы попросите его сделать это. Это особенно часто встречается в случаях, когда URL-путь совпадает, но содержимое изменяется (например, динамические изображения).
Вы думаете, что сценарий такой?
Путь к сценарию в файловой системе не обязательно напрямую связан с URL-путем к сценарию. Убедитесь, что у вас есть правильный каталог, даже если вам нужно написать короткий тестовый сценарий, чтобы проверить это. Кроме того, уверены ли вы, что изменяете правильный файл? Если вы не видите никакого эффекта от ваших изменений, возможно, вы изменяете другой файл или загружаете файл не в то место. (Это, кстати, самая частая моя причина таких неприятностей;)
Вы используете его
CGI.pm
или его производное?Если ваша проблема связана с разбором ввода CGI , и вы не используете широко испытанный модуль , как
CGI.pm
,CGI::Request
,CGI::Simple
илиCGI::Lite
, использовать модуль и получить от жизни.CGI.pm
имеетcgi-lib.pl
режим совместимости, который может помочь вам решить проблемы ввода из-за более старых реализаций синтаксического анализатора CGI.Вы использовали абсолютные пути?
Если вы выполняете внешние команды с помощью
system
обратных тиков или других средств IPC, вы должны использовать абсолютный путь к внешней программе. Вы не только точно знаете, что используете, но и избегаете некоторых проблем с безопасностью. Если вы открываете файлы для чтения или записи, используйте абсолютный путь. У сценария CGI может быть иное представление о текущем каталоге, чем у вас. В качестве альтернативы вы можете сделать явное,chdir()
чтобы поставить вас в нужное место.Вы проверяли возвращаемые значения?
Большинство функций Perl сообщают вам, работали они или нет, и устанавливают их
$!
при ошибке. Вы проверяли возвращаемое значение и искали$!
сообщения об ошибках? Вы проверяли$@
, употребляли ли выeval
?Какую версию Perl вы используете?
Последняя стабильная версия Perl - 5.28 (или нет, в зависимости от того, когда она в последний раз редактировалась). Вы используете старую версию? В разных версиях Perl могут быть разные идеи предупреждений.
Какой веб-сервер вы используете?
В одной и той же ситуации разные серверы могут действовать по-разному. Один и тот же серверный продукт может работать по-разному в разных конфигурациях. Включите как можно больше этой информации в любой запрос о помощи.
Вы проверяли документацию по серверу?
Серьезные программисты CGI должны знать о сервере как можно больше, включая не только особенности и поведение сервера, но и локальную конфигурацию. Документация для вашего сервера может быть недоступна, если вы используете коммерческий продукт. В противном случае документация должна быть на вашем сервере. Если это не так, поищите его в Интернете.
Вы искали в архивах
comp.infosystems.www.authoring.cgi
?Это было полезно, но все хорошие плакаты либо умерли, либо рассеялись.
Вероятно, у кого-то уже была ваша проблема и что кто-то (возможно, я) ответил на нее в этой группе новостей. Хотя эта группа новостей уже пережила свой расцвет, накопленная мудрость из прошлого иногда может быть полезной.
Можете ли вы воспроизвести проблему с помощью короткого тестового сценария?
В больших системах может быть сложно отследить ошибку, поскольку происходит так много всего. Постарайтесь воспроизвести проблемное поведение как можно более коротким сценарием. Знание проблемы - это большая часть решения. Это, безусловно, может занять много времени, но вы еще не нашли проблему и у вас заканчиваются варианты. :)
Вы решили пойти в кино?
Шутки в сторону. Иногда мы можем настолько увлечься проблемой, что у нас развивается «сужение восприятия» (туннельное зрение). Сделав перерыв, выпив чашку кофе или взорвав плохих парней в [Duke Nukem, Quake, Doom, Halo, COD], вы можете по-новому взглянуть на проблему.
Вы озвучили проблему?
Снова серьезно. Иногда объяснение проблемы вслух приводит нас к нашим собственным ответам. Поговорите с пингвином (плюшевая игрушка), потому что ваши коллеги не слушают. Если вы заинтересованы в этом как в серьезном инструменте отладки (и я рекомендую его, если вы еще не нашли проблему), вы также можете прочитать Психологию компьютерного программирования .
источник
$|=1
вместо$|++
?$|=1
вместо$|++
? На самом деле это не имеет значения, и даже тогда$|
это волшебно.use strict
как правило, полезно использовать в любое время, тогда как использованиеfatalsToBrowser
может быть не рекомендовано в производственной среде, особенно если вы используетеdie
.Думаю, стоит упомянуть и CGI :: Debug .
источник
die
операторы и другие фатальные ошибки во время выполнения и компиляцииSTDERR
, которые могут быть трудно найти и могут быть связаны с сообщениями с других веб-страниц на вашем сайте. Пока вы отлаживаете свой скрипт, рекомендуется каким-то образом отображать сообщения о фатальных ошибках в вашем браузере.Один из способов сделать это - позвонить
вверху вашего скрипта. Этот вызов установит
$SIG{__DIE__}
обработчик (см. Perlvar ), отображающий фатальные ошибки в вашем браузере, при необходимости добавив к нему действительный заголовок. Еще один трюк отладки CGI, который я использовал до того, как услышал о нем,CGI::Carp
заключался в использованииeval
со средствамиDATA
и__END__
в сценарии для обнаружения ошибок времени компиляции:Этот более подробный метод имеет небольшое преимущество
CGI::Carp
в том, что он выявляет больше ошибок времени компиляции.Обновление: я никогда не использовал его, но похоже
CGI::Debug
, как предложил Микаэль С., также очень полезный и настраиваемый инструмент для этой цели.источник
<DATA>
волшебный дескриптор файла, который читает текущий скрипт, начиная с__END__
. Join предоставляет контекст списка, поэтому <fh> возвращает массив, по одной строке на элемент. Затем join соединяет их (соединяя их с помощью ""). Наконец, eval.eval join(q{}, <DATA>);
Интересно, почему никто не упомянул
PERLDB_OPTS
названный вариантRemotePort
; хотя, по общему признанию, в сети не так много рабочих примеров (RemotePort
даже не упомянутых в perldebug ) - и мне было довольно проблематично придумать этот, но вот оно (это пример Linux).Чтобы сделать правильный пример, сначала мне нужно было что-то, что могло бы выполнять очень простую симуляцию веб-сервера CGI, предпочтительно через одну командную строку. После нахождения веб-сервера простой командной строки для запуска cgis. (perlmonks.org) , я обнаружил, что IO :: All - Tiny Web Server подходит для этого теста.
Здесь я буду работать в
/tmp
каталоге; сценарий CGI будет/tmp/test.pl
(включен ниже). Обратите внимание, чтоIO::All
сервер будет обслуживать исполняемые файлы только в том же каталоге, что и CGI, поэтомуchmod +x test.pl
здесь это необходимо. Итак, чтобы выполнить обычный тестовый запуск CGI, я меняю каталог на/tmp
в терминале и запускаю там однострочный веб-сервер:Команда веб-сервера заблокируется в терминале, а в противном случае запустит веб-сервер локально (на 127.0.0.1 или
localhost
) - после этого я могу перейти в веб-браузер и запросить этот адрес:... и я должен наблюдать за
print
s, создаваемымиtest.pl
при загрузке - и отображении - в веб-браузере.Теперь, чтобы отлаживать этот сценарий
RemotePort
, сначала нам понадобится слушатель в сети, через который мы будем взаимодействовать с отладчиком Perl; мы можем использовать инструмент командной строкиnetcat
(выnc
видели это здесь: Perl 如何 удаленная отладка? ). Итак, сначала запуститеnetcat
прослушиватель в одном терминале - где он будет блокировать и ждать соединений на порту 7234 (который будет нашим портом отладки):Затем мы хотели бы
perl
начать в режиме отладки сRemotePort
, когдаtest.pl
был вызван (даже в режиме CGI через сервер). В Linux это можно сделать с помощью следующего сценария «оболочки shebang», который здесь также должен быть включен/tmp
и должен быть исполняемым:Это своего рода хитрая вещь - см. Сценарий оболочки - Как я могу использовать переменные среды в моем shebang? - Обмен стеков Unix и Linux . Но хитрость здесь , кажется, не раскошелиться на
perl
интерпретатор , который ручкамиtest.pl
- так , как только мы попали его, мы не делаемexec
, но вместо этого мы называемperl
«ясно», и в основном «источник» нашtest.pl
скрипт с помощьюdo
(см Как запустить Сценарий Perl из сценария Perl? ).Теперь, когда мы имеем
perldbgcall.sh
в/tmp
- мы можем изменитьtest.pl
файл, так что он относится к этому исполняемому файлу на его притон линии (вместо обычного интерпретатора Perl) - здесь/tmp/test.pl
изменен следующим образом:Теперь оба
test.pl
и его новый обработчик shebangperldbgcall.sh
находятся в/tmp
; и у нас естьnc
прослушивание отладочных подключений на порту 7234 - так что мы можем, наконец, открыть другое окно терминала, сменить каталог/tmp
и запустить однострочный веб-сервер (который будет прослушивать веб-подключения на порту 8080) там:После этого мы можем зайти в наш веб-браузер и запросить тот же адрес
http://127.0.0.1:8080/test.pl
. Однако теперь, когда веб-сервер пытается выполнить сценарий, он будет делать это черезperldbgcall.sh
shebang, который запускаетсяperl
в режиме удаленного отладчика. Таким образом, выполнение скрипта будет приостановлено - и тогда веб-браузер заблокируется в ожидании данных. Теперь мы можем переключиться наnetcat
терминал, и мы должны увидеть знакомый текст отладчика Perl - однако вывод черезnc
:Как показано во фрагменте, теперь мы в основном используем
nc
в качестве «терминала» - поэтому мы можем ввестиr
(и Enter) для «запустить» - и скрипт запустится и выполнит оператор точки останова (см. Также В perl, в чем разница между $ DB :: single = 1 и 2? ), Прежде чем снова остановиться (обратите внимание, что в этот момент браузер все равно будет заблокирован).Итак, теперь мы можем, скажем, пройти остальную часть
test.pl
черезnc
терминал:... однако и в этот момент браузер блокирует и ожидает данных. Только после выхода из отладчика
q
:... перестает ли браузер блокироваться - и, наконец, отображает (полный) вывод
test.pl
:Конечно, такую отладку можно выполнить даже без запуска веб-сервера, однако самое интересное здесь в том, что мы вообще не касаемся веб-сервера; мы запускаем выполнение "изначально" (для CGI) из веб-браузера - и единственное изменение, необходимое в самом сценарии CGI, - это изменение shebang (и, конечно же, наличие сценария оболочки shebang в качестве исполняемого файла в том же каталог).
Что ж, надеюсь, это кому-то поможет - я бы с удовольствием наткнулся на это, а не писал сам.
:)
Ура!
источник
Для меня я использую log4perl . Это довольно удобно и просто.
источник
Честно говоря, вы можете делать все самое интересное над этим постом. ХОТЯ, самым простым и наиболее активным решением, которое я нашел, было просто "распечатать его".
В примере: (Нормальный код)
Чтобы узнать, делает ли он то, что я действительно хочу: (Устранение неполадок)
источник
Вероятно, также стоит упомянуть, что Perl всегда сообщает вам, в какой строке возникает ошибка, когда вы выполняете сценарий Perl из командной строки. (Например, сеанс SSH)
Я обычно так и делаю, если ничего не помогает. Я подключусь к серверу по SSH и вручную выполню сценарий Perl. Например:
Если есть проблема, Perl сообщит вам об этом. Этот метод отладки устраняет любые проблемы, связанные с правами доступа к файлам, или проблемы с веб-браузером или веб-сервером.
источник
Вы можете запустить perl cgi-скрипт в терминале, используя следующую команду
Он интерпретирует код и предоставляет результат с кодом HTML. Он сообщит об ошибке, если таковая имеется.
источник
perl -c filename
действительно проверяет только синтаксис. Ноperl filename
распечатывает вывод HTML. Хотя нет гарантии, что ошибки 500 CGI не будет, но это хороший первый тест.