Làm cách nào để khắc phục sự cố tập lệnh Perl CGI của tôi?


100

Tôi có một tập lệnh Perl không hoạt động và tôi không biết làm cách nào để bắt đầu thu hẹp vấn đề. Tôi có thể làm gì?


Lưu ý: Tôi đang thêm câu hỏi vì tôi thực sự muốn thêm câu trả lời rất dài của mình vào Stackoverflow. Tôi tiếp tục liên kết bên ngoài với nó trong các câu trả lời khác và nó xứng đáng ở đây. Đừng ngại chỉnh sửa câu trả lời của tôi nếu bạn có điều gì đó để bổ sung.


5
@ Evan - quan điểm của tôi chỉ đơn giản là ngay cả khi không CW nó vẫn có thể chỉnh sửa - nếu bạn có đủ nghiệp; 100 cho CW, 2k nếu không. Vì vậy, bây giờ bạn có 2060, bạn sẽ có thể chỉnh sửa các bài đăng không phải CW.
Marc Gravell

1
@ Evan, những điểm ma thuật được liệt kê trong tooltips trong cột bên tay phải ở đây: stackoverflow.com/privileges
CJM

Nếu trình duyệt web của bạn hiển thị nhiễu dòng, nó có thể đang in tập lệnh perl. Trong trường hợp đó, hãy xem stackoverflow.com/questions/2621161/…
Andrew Grimm

Câu trả lời:


129

Câu trả lời này được thiết kế như một khuôn khổ chung để giải quyết các vấn đề với tập lệnh Perl CGI và ban đầu xuất hiện trên Perlmonks dưới dạng Khắc phục sự cố tập lệnh Perl CGI . Nó không phải là một hướng dẫn đầy đủ cho mọi vấn đề mà bạn có thể gặp phải, cũng không phải là một hướng dẫn về cách xử lý lỗi. Đó chỉ là đỉnh cao của kinh nghiệm gỡ lỗi tập lệnh CGI của tôi trong hai mươi (cộng!) Năm. Trang này dường như có nhiều ngôi nhà khác nhau và tôi dường như quên rằng nó tồn tại, vì vậy tôi đang thêm nó vào StackOverflow. Bạn có thể gửi bất kỳ nhận xét hoặc đề xuất nào cho tôi tại bdfoy@cpan.org. Nó cũng là wiki cộng đồng, nhưng đừng quá điên rồ. :)


Bạn có đang sử dụng các tính năng được tích hợp sẵn của Perl để giúp bạn tìm ra sự cố không?

Bật cảnh báo để Perl cảnh báo bạn về những phần có vấn đề trong mã của bạn. Bạn có thể thực hiện việc này từ dòng lệnh với -wnút chuyển để không phải thay đổi bất kỳ mã nào hoặc thêm pragma vào mọi tệp:

 % perl -w program.pl

Tuy nhiên, bạn nên buộc mình phải luôn xóa mã có vấn đề bằng cách thêm warningspragma vào tất cả các tệp của mình:

 use warnings;

Nếu bạn cần thêm thông tin ngoài thông báo cảnh báo ngắn, hãy sử dụng diagnosticspragma để có thêm thông tin hoặc xem trong tài liệu perldiag :

 use diagnostics;

Bạn có xuất tiêu đề CGI hợp lệ trước không?

Máy chủ đang mong đợi đầu ra đầu tiên từ tập lệnh CGI là tiêu đề CGI. Thông thường, điều đó có thể đơn giản như print "Content-type: text/plain\n\n";hoặc với CGI.pm và các dẫn xuất của nó print header(),. Một số máy chủ nhạy cảm với đầu ra lỗi (bật STDERR) hiển thị trước đầu ra chuẩn (bật STDOUT).

Thử gửi lỗi tới trình duyệt

Thêm dòng này

 use CGI::Carp 'fatalsToBrowser';

vào kịch bản của bạn. Điều này cũng gửi lỗi biên dịch đến cửa sổ trình duyệt. Hãy chắc chắn loại bỏ điều này trước khi chuyển sang môi trường sản xuất, vì thông tin bổ sung có thể là một rủi ro bảo mật.

Nhật ký lỗi đã nói gì?

Máy chủ lưu giữ nhật ký lỗi (hoặc ít nhất là chúng nên). Lỗi đầu ra từ máy chủ và từ tập lệnh của bạn sẽ hiển thị ở đó. Tìm nhật ký lỗi và xem nó nói gì. Không có một nơi tiêu chuẩn cho các tệp nhật ký. Tìm trong cấu hình máy chủ để biết vị trí của chúng hoặc hỏi quản trị viên máy chủ. Bạn cũng có thể sử dụng các công cụ như CGI :: Cá chép để giữ các tệp nhật ký của riêng bạn.

Các quyền của tập lệnh là gì?

Nếu bạn thấy các lỗi như "Quyền bị từ chối" hoặc "Phương pháp không được triển khai", điều đó có thể có nghĩa là tập lệnh của bạn không thể đọc và thực thi được bởi người dùng máy chủ web. Về hương vị của Unix, thay đổi chế độ để 755 được đề nghị: chmod 755 filename. Không bao giờ đặt chế độ thành 777!

Bạn đang sử dụng use strict?

Hãy nhớ rằng Perl tự động tạo các biến khi bạn sử dụng chúng lần đầu tiên. Đây là một tính năng, nhưng đôi khi có thể gây ra lỗi nếu bạn nhập sai tên biến. Pragma use strictsẽ giúp bạn tìm ra những lỗi đó. Thật khó chịu cho đến khi bạn quen với nó, nhưng lập trình của bạn sẽ cải thiện đáng kể sau một thời gian và bạn có thể thoải mái mắc các lỗi khác nhau.

Tập lệnh có biên dịch không?

Bạn có thể kiểm tra lỗi biên dịch bằng cách sử dụng công -c tắc. Tập trung vào các lỗi đầu tiên được báo cáo. Rửa sạch, lặp lại. Nếu bạn gặp phải lỗi thực sự lạ, hãy kiểm tra để đảm bảo rằng tập lệnh của bạn có phần cuối dòng phù hợp. Nếu bạn FTP ở chế độ nhị phân, kiểm tra từ CVS hoặc thứ gì khác không xử lý bản dịch cuối dòng, máy chủ web có thể thấy tập lệnh của bạn là một dòng lớn. Chuyển các tập lệnh Perl ở chế độ ASCII.

Tập lệnh có phàn nàn về các phụ thuộc không an toàn không?

Nếu tập lệnh của bạn phàn nàn về các phụ thuộc không an toàn, có thể bạn đang sử dụng công -Ttắc để bật chế độ taint, đây là một điều tốt vì nó giúp bạn truyền dữ liệu chưa được kiểm tra vào trình bao. Nếu nó phàn nàn, nó đang làm công việc của mình để giúp chúng tôi viết những đoạn script an toàn hơn. Bất kỳ dữ liệu nào có nguồn gốc từ bên ngoài chương trình (tức là môi trường) được coi là bị ô nhiễm. Các biến môi trường như PATHLD_LIBRARY_PATH đặc biệt rắc rối. Bạn phải đặt chúng thành giá trị an toàn hoặc bỏ đặt chúng hoàn toàn, như tôi khuyên bạn nên. Dù sao thì bạn cũng nên sử dụng đường dẫn tuyệt đối. Nếu việc kiểm tra chất bẩn phàn nàn về điều gì khác, hãy đảm bảo rằng bạn đã gỡ bỏ dữ liệu. Xem trang người đàn ông perlsec để biết chi tiết.

Điều gì xảy ra khi bạn chạy nó từ dòng lệnh?

Tập lệnh có xuất ra những gì bạn mong đợi khi chạy từ dòng lệnh không? Đầu ra tiêu đề có đầu tiên, theo sau là một dòng trống? Hãy nhớ rằng điều đó STDERRcó thể được hợp nhất với STDOUT nếu bạn đang ở trên một thiết bị đầu cuối (ví dụ: một phiên tương tác) và do bộ đệm có thể hiển thị theo một thứ tự lộn xộn. Bật tính năng autoflush của Perl bằng cách đặt $|thành giá trị true. Thông thường bạn có thể thấy $|++;trong các chương trình CGI. Sau khi thiết lập, mọi bản in và ghi sẽ ngay lập tức được chuyển đến đầu ra chứ không phải được lưu vào bộ đệm. Bạn phải thiết lập điều này cho mỗi bộ xử lý tệp. Sử dụng selectđể thay đổi xử lý tệp mặc định, như sau:

$|++;                            #sets $| for STDOUT
$old_handle = select( STDERR );  #change to STDERR
$|++;                            #sets $| for STDERR
select( $old_handle );           #change back to STDOUT

Dù bằng cách nào, đầu ra đầu tiên phải là tiêu đề CGI, theo sau là một dòng trống.

Điều gì xảy ra khi bạn chạy nó từ dòng lệnh với môi trường giống như CGI?

Môi trường máy chủ web thường hạn chế hơn nhiều so với môi trường dòng lệnh của bạn và có thêm thông tin về yêu cầu. Nếu tập lệnh của bạn chạy tốt từ dòng lệnh, bạn có thể thử mô phỏng môi trường máy chủ web. Nếu sự cố xuất hiện, bạn có sự cố về môi trường.

Bỏ đặt hoặc xóa các biến này

  • PATH
  • LD_LIBRARY_PATH
  • tất cả các ORACLE_*biến

Đặt các biến này

  • REQUEST_METHOD(thiết lập để GET, HEADhoặc POSTnếu thích hợp)
  • SERVER_PORT (thường đặt thành 80)
  • REMOTE_USER (nếu bạn đang làm công cụ truy cập được bảo vệ)

Các phiên bản gần đây của CGI.pm(> 2,75) yêu cầu -debugcờ phải có hành vi cũ (hữu ích), vì vậy bạn có thể phải thêm nó vào mục CGI.pmnhập của mình .

use CGI qw(-debug)

Bạn đang sử dụng die()hoặc warn?

Các hàm đó được in ra STDERRtrừ khi bạn đã định nghĩa lại chúng. Chúng cũng không xuất ra tiêu đề CGI. Bạn có thể nhận được chức năng tương tự với các gói như CGI :: Cá chép

Điều gì xảy ra sau khi bạn xóa bộ nhớ cache của trình duyệt?

Nếu bạn cho rằng tập lệnh của mình đang làm đúng và khi thực hiện yêu cầu theo cách thủ công, bạn nhận được đầu ra phù hợp, thì trình duyệt có thể là thủ phạm. Xóa bộ nhớ cache và đặt kích thước bộ nhớ cache thành 0 trong khi kiểm tra. Hãy nhớ rằng một số trình duyệt thực sự ngu ngốc và sẽ không thực sự tải lại nội dung mới ngay cả khi bạn yêu cầu nó làm như vậy. Điều này đặc biệt phổ biến trong trường hợp đường dẫn URL giống nhau, nhưng nội dung thay đổi (ví dụ: hình ảnh động).

Kịch bản có đúng như bạn nghĩ không?

Đường dẫn hệ thống tệp đến một tập lệnh không nhất thiết phải liên quan trực tiếp đến đường dẫn URL đến tập lệnh. Đảm bảo rằng bạn có đúng thư mục, ngay cả khi bạn phải viết một đoạn mã thử nghiệm ngắn để kiểm tra điều này. Hơn nữa, bạn có chắc chắn rằng bạn đang sửa đổi đúng tệp không? Nếu bạn không thấy bất kỳ tác dụng nào với các thay đổi của mình, có thể bạn đang sửa đổi một tệp khác hoặc tải tệp lên không đúng nơi. (Nhân tiện, đây là nguyên nhân thường xuyên nhất của tôi gây ra rắc rối như vậy;)

Bạn đang sử dụng CGI.pm, hay một dẫn xuất của nó?

Nếu vấn đề của bạn có liên quan đến phân tích đầu vào CGI và bạn không sử dụng một mô-đun thử nghiệm rộng rãi như CGI.pm, CGI::Request, CGI::Simplehoặc CGI::Lite, sử dụng các mô-đun và nhận được về với cuộc sống. CGI.pmcgi-lib.plchế độ tương thích có thể giúp bạn giải quyết các vấn đề đầu vào do triển khai trình phân tích cú pháp CGI cũ hơn.

Bạn đã sử dụng đường dẫn tuyệt đối?

Nếu bạn đang chạy các lệnh bên ngoài với system, dấu tích quay lại hoặc các tiện ích IPC khác, bạn nên sử dụng một đường dẫn tuyệt đối đến chương trình bên ngoài. Bạn không chỉ biết chính xác những gì bạn đang chạy mà còn tránh được một số vấn đề về bảo mật. Nếu bạn đang mở tệp để đọc hoặc ghi, hãy sử dụng một đường dẫn tuyệt đối. Tập lệnh CGI có thể có ý tưởng khác về thư mục hiện tại với bạn. Ngoài ra, bạn có thể làm rõ ràng chdir()để đưa bạn vào đúng vị trí.

Bạn đã kiểm tra các giá trị trả lại của mình chưa?

Hầu hết các hàm Perl sẽ cho bạn biết nếu chúng hoạt động hay không và sẽ đặt $!khi thất bại. Bạn đã kiểm tra giá trị trả về và kiểm tra $!thông báo lỗi chưa? Bạn đã kiểm tra $@xem mình đang sử dụng evalchưa?

Bạn đang sử dụng phiên bản Perl nào?

Phiên bản ổn định mới nhất của Perl là 5.28 (hoặc không, tùy thuộc vào thời điểm điều này được chỉnh sửa lần cuối). Bạn đang sử dụng phiên bản cũ hơn? Các phiên bản khác nhau của Perl có thể có các ý tưởng cảnh báo khác nhau.

Bạn đang sử dụng máy chủ web nào?

Các máy chủ khác nhau có thể hoạt động khác nhau trong cùng một tình huống. Cùng một sản phẩm máy chủ có thể hoạt động khác nhau với các cấu hình khác nhau. Bao gồm càng nhiều thông tin này càng tốt trong bất kỳ yêu cầu trợ giúp nào.

Bạn đã kiểm tra tài liệu máy chủ chưa?

Các lập trình viên CGI nghiêm túc nên biết càng nhiều càng tốt về máy chủ - không chỉ bao gồm các tính năng và hành vi của máy chủ mà còn cả cấu hình cục bộ. Tài liệu về máy chủ của bạn có thể không có sẵn cho bạn nếu bạn đang sử dụng sản phẩm thương mại. Nếu không, tài liệu sẽ nằm trên máy chủ của bạn. Nếu không, hãy tìm nó trên web.

Bạn đã tìm kiếm các kho lưu trữ của comp.infosystems.www.authoring.cgi?

Việc sử dụng này rất hữu ích nhưng tất cả các áp phích tốt đều đã chết hoặc biến mất.

Có khả năng ai đó đã gặp vấn đề của bạn trước đây và ai đó (có thể là tôi) đã giải đáp vấn đề đó trong nhóm tin này. Mặc dù nhóm tin này đã qua thời kỳ hoàng kim, nhưng những thông thái thu thập được từ quá khứ đôi khi có thể hữu ích.

Bạn có thể tái tạo sự cố bằng một tập lệnh thử nghiệm ngắn không?

Trong các hệ thống lớn, có thể khó tìm ra lỗi vì có rất nhiều thứ đang xảy ra. Cố gắng tái tạo hành vi sự cố bằng tập lệnh ngắn nhất có thể. Biết được vấn đề là cách khắc phục hầu hết. Điều này chắc chắn tốn thời gian nhưng bạn vẫn chưa tìm ra vấn đề và sắp hết các lựa chọn. :)

Bạn đã quyết định đi xem một bộ phim?

Nghiêm túc. Đôi khi chúng ta có thể bị cuốn vào vấn đề đến mức chúng ta phát triển "thu hẹp tri giác" (tầm nhìn đường hầm). Nghỉ giải lao, uống một tách cà phê hoặc đánh bại một số kẻ xấu trong [Duke Nukem, Quake, Doom, Halo, COD] có thể cung cấp cho bạn góc nhìn mới mẻ mà bạn cần để tiếp cận lại vấn đề.

Bạn đã nói ra vấn đề chưa?

Nghiêm túc một lần nữa. Đôi khi giải thích vấn đề một cách to tiếng sẽ dẫn chúng ta đến câu trả lời của chính mình. Nói chuyện với chim cánh cụt (đồ chơi sang trọng) vì đồng nghiệp của bạn không lắng nghe. Nếu bạn quan tâm đến công cụ này như một công cụ gỡ lỗi nghiêm trọng (và tôi khuyên bạn nên sử dụng nó nếu bạn vẫn chưa tìm ra vấn đề ngay bây giờ), bạn cũng có thể thích đọc Tâm lý học của lập trình máy tính .


4
Đừng ngại chỉnh sửa câu trả lời của tôi nếu bạn có điều gì đó để bổ sung.
brian d foy

Có vẻ như bạn có thể muốn xóa liên kết đến Câu hỏi thường gặp về meta CGI. 5.12.1 có được coi là "ổn định" không?
Snake Plissken

1
Tại sao không $|=1thay vì $|++?
reinierpost

Tại sao $|=1thay vì $|++? Nó không thực sự tạo ra sự khác biệt, và thậm chí sau đó, $|thật kỳ diệu.
brian d foy

2
Câu trả lời rất hay, tôi nghĩ có thể đáng nói rằng một số giải pháp trong số này chỉ là để khắc phục sự cố và không được đưa vào mã sản xuất. use strictNói chung là tốt để sử dụng mọi lúc, trong khi việc sử dụng fatalsToBrowsercó thể không được khuyến cáo trong quá trình sản xuất, đặc biệt nếu bạn đang sử dụng die.
vol7ron

10

Tôi nghĩ CGI :: Debug cũng đáng được nhắc đến.


Thật không may, tôi chỉ có thể chỉnh sửa câu hỏi, không phải câu trả lời.
Mikael S

7

Bạn có đang sử dụng trình xử lý lỗi trong khi gỡ lỗi không?

diecác câu lệnh và các lỗi thời gian chạy và thời gian biên dịch nghiêm trọng khác được in ra STDERR, có thể khó tìm và có thể bị lẫn với các thông báo từ các trang web khác trên trang web của bạn. Trong khi gỡ lỗi tập lệnh của mình, bạn nên làm cách nào đó để hiển thị thông báo lỗi nghiêm trọng trong trình duyệt của mình.

Một cách để làm điều này là gọi

   use CGI::Carp qw(fatalsToBrowser);

ở đầu tập lệnh của bạn. Lệnh gọi đó sẽ cài đặt một $SIG{__DIE__}trình xử lý (xem perlvar ) hiển thị các lỗi nghiêm trọng trong trình duyệt của bạn, thêm vào đó một tiêu đề hợp lệ nếu cần. Một thủ thuật gỡ lỗi CGI khác mà tôi đã từng sử dụng trước đây CGI::Carplà sử dụng evalcác phương tiện DATA__END__phương tiện trên script để bắt lỗi thời gian biên dịch:

   #!/usr/bin/perl
   eval join'', <DATA>;
   if ($@) { print "Content-type: text/plain:\n\nError in the script:\n$@\n; }
   __DATA__
   # ... actual CGI script starts here

Kỹ thuật dài dòng hơn này có một lợi thế nhỏ CGI::Carpở chỗ nó sẽ mắc nhiều lỗi thời gian biên dịch hơn.

Cập nhật: Tôi chưa bao giờ sử dụng nó, nhưng có vẻ như CGI::Debug, như Mikael S đề xuất, cũng là một công cụ rất hữu ích và có thể cấu hình cho mục đích này.


3
@Ether: <DATA>là một trình xử lý tệp ma thuật đọc kịch bản hiện tại bắt đầu bằng __END__. Tham gia cung cấp cho nó ngữ cảnh danh sách, vì vậy <fh> trả về một mảng, một dòng cho mỗi mục. Sau đó, phép nối đặt nó lại với nhau (nối nó với ''). Cuối cùng, đánh giá.
derobert

@Ether: Một cách dễ đọc hơn để viết dòng 2 sẽ là:eval join(q{}, <DATA>);
derobert 09/09

@derobert: thực ra, __DATA__ là mã thông báo được sử dụng để bắt đầu phần dữ liệu, không phải __END__ (Tôi nghĩ đó là sự nhầm lẫn của tôi).
Ether

1
@Ether: Thực ra thì, cả hai đều hoạt động trong tập lệnh cấp cao nhất (theo trang perldata). Nhưng vì DATA được ưu tiên hơn, tôi đã thay đổi câu trả lời.
derobert

@derobert: cảm ơn vì liên kết doc; Tôi không biết về hoạt động tương thích ngược của __END__!
Ether

7

Tôi tự hỏi tại sao không ai đề cập đến PERLDB_OPTStùy chọn được gọi là RemotePort; mặc dù phải thừa nhận rằng không có nhiều ví dụ hoạt động trên web ( RemotePortthậm chí không được đề cập trong perldebug ) - và thật là có vấn đề đối với tôi khi đưa ra cái này, nhưng đây là nó (nó là một ví dụ Linux).

Để làm một ví dụ thích hợp, trước tiên tôi cần một thứ có thể thực hiện một mô phỏng rất đơn giản của máy chủ web CGI, tốt nhất là thông qua một dòng lệnh duy nhất. Sau khi tìm thấy máy chủ web dòng lệnh đơn giản để chạy cgis. (perlmonks.org) , tôi thấy IO :: Tất cả - Máy chủ web nhỏ có thể áp dụng cho thử nghiệm này.

Ở đây, tôi sẽ làm việc trong /tmpthư mục; kịch bản CGI sẽ được /tmp/test.pl(bao gồm bên dưới). Lưu ý rằng IO::Allmáy chủ sẽ chỉ phục vụ các tệp thực thi trong cùng thư mục với CGI, vì vậy chmod +x test.plở đây là bắt buộc. Vì vậy, để thực hiện chạy thử nghiệm CGI thông thường, tôi thay đổi thư mục thành /tmptrong thiết bị đầu cuối và chạy máy chủ web một lớp ở đó:

$ cd /tmp
$ perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'

Lệnh máy chủ web sẽ chặn trong thiết bị đầu cuối và nếu không sẽ khởi động máy chủ web cục bộ (trên 127.0.0.1 hoặc localhost) - sau đó, tôi có thể truy cập trình duyệt web và yêu cầu địa chỉ này:

http://127.0.0.1:8080/test.pl

... và tôi nên quan sát những thứ printđược thực hiện bằng cách test.pltải - và hiển thị - trong trình duyệt web.


Bây giờ, để gỡ lỗi tập lệnh này RemotePort, trước tiên chúng ta cần một trình lắng nghe trên mạng, qua đó chúng ta sẽ tương tác với trình gỡ lỗi Perl; chúng ta có thể sử dụng công cụ dòng lệnh netcat( nc, đã thấy ở đây: Perl 如何 remote debug? ). Vì vậy, trước tiên hãy chạy trình netcatlắng nghe trong một thiết bị đầu cuối - nơi nó sẽ chặn và đợi các kết nối trên cổng 7234 (sẽ là cổng gỡ lỗi của chúng tôi):

$ nc -l 7234

Sau đó, chúng tôi muốn perlbắt đầu ở chế độ gỡ lỗi với RemotePort, khi nó test.plđã được gọi (ngay cả trong chế độ CGI, thông qua máy chủ). Điều này, trong Linux, có thể được thực hiện bằng cách sử dụng tập lệnh "shebang wrapper" sau - tập lệnh này cũng cần phải có trong đó /tmpphải được thực thi:

cd /tmp

cat > perldbgcall.sh <<'EOF'
#!/bin/bash
PERLDB_OPTS="RemotePort=localhost:7234" perl -d -e "do '$@'"
EOF

chmod +x perldbgcall.sh

Đây là một điều khó khăn - hãy xem tập lệnh shell - Làm cách nào để sử dụng các biến môi trường trong shebang của tôi? - Unix & Linux Stack Exchange . Tuy nhiên, mẹo ở đây dường như không phải là phân nhánh trình perlthông dịch xử lý test.pl - vì vậy một khi chúng tôi nhấn nó, chúng tôi sẽ không exec, mà thay vào đó chúng tôi gọi là perl"rõ ràng" và về cơ bản là "nguồn" test.pltập lệnh của chúng tôi bằng cách sử dụng do(xem Cách tôi chạy Tập lệnh Perl từ bên trong tập lệnh Perl? ).

Bây giờ chúng ta đã có perldbgcall.shtrong đó /tmp- chúng ta có thể thay đổi test.pltệp để nó tham chiếu đến tệp thực thi này trên dòng shebang của nó (thay vì trình thông dịch Perl thông thường) - ở đây được /tmp/test.plsửa đổi do đó:

#!./perldbgcall.sh

# this is test.pl

use 5.10.1;
use warnings;
use strict;

my $b = '1';
my $a = sub { "hello $b there" };
$b = '2';
print "YEAH " . $a->() . " CMON\n";
$b = '3';
print "CMON " . &$a . " YEAH\n";

$DB::single=1;  # BREAKPOINT

$b = '4';
print "STEP " . &$a . " NOW\n";
$b = '5';
print "STEP " . &$a . " AGAIN\n";

Bây giờ, cả hai test.plvà trình xử lý shebang mới của nó perldbgcall.sh, đều ở trong /tmp; và chúng tôi đã nclắng nghe các kết nối gỡ lỗi trên cổng 7234 - vì vậy cuối cùng chúng tôi có thể mở một cửa sổ đầu cuối khác, thay đổi thư mục thành /tmpvà chạy máy chủ web một lớp (sẽ lắng nghe các kết nối web trên cổng 8080) ở đó:

cd /tmp
perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 ? "./$1 |" : $1) if /^GET \/(.*) / })'

Sau khi hoàn tất, chúng tôi có thể truy cập trình duyệt web của mình và yêu cầu địa chỉ tương tự http://127.0.0.1:8080/test.pl,. Tuy nhiên, bây giờ khi máy chủ web cố gắng thực thi tập lệnh, nó sẽ thực hiện điều đó thông qua perldbgcall.shshebang - sẽ bắt đầu perlở chế độ trình gỡ lỗi từ xa. Do đó, quá trình thực thi tập lệnh sẽ tạm dừng - và do đó trình duyệt web sẽ khóa, chờ dữ liệu. Bây giờ chúng ta có thể chuyển sang netcatthiết bị đầu cuối và chúng ta sẽ thấy văn bản trình gỡ lỗi Perl quen thuộc - tuy nhiên, xuất thông qua nc:

$ nc -l 7234

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(-e:1):   do './test.pl'
  DB<1> r
main::(./test.pl:29):   $b = '4';
  DB<1>

Như đoạn mã hiển thị, về cơ bản chúng ta sử dụng ncnhư một "terminal" - vì vậy chúng ta có thể nhập r(và Enter) cho "run" - và tập lệnh sẽ chạy lên thực hiện câu lệnh breakpoint (xem thêm Trong perl, sự khác biệt giữa $ DB :: single = 1 and 2? ), Trước khi dừng lại (lưu ý tại thời điểm đó, trình duyệt vẫn sẽ khóa).

Vì vậy, bây giờ chúng ta có thể, nói, bước qua phần còn lại của test.pl, thông qua ncthiết bị đầu cuối:

....
main::(./test.pl:29):   $b = '4';
  DB<1> n
main::(./test.pl:30):   print "STEP " . &$a . " NOW\n";
  DB<1> n
main::(./test.pl:31):   $b = '5';
  DB<1> n
main::(./test.pl:32):   print "STEP " . &$a . " AGAIN\n";
  DB<1> n
Debugged program terminated.  Use q to quit or R to restart,
  use o inhibit_exit to avoid stopping after program termination,
  h q, h R or h o to get additional info.
  DB<1>

... tuy nhiên, cũng tại thời điểm này, trình duyệt sẽ khóa và chờ dữ liệu. Chỉ sau khi chúng tôi thoát khỏi trình gỡ lỗi với q:

  DB<1> q
$

... trình duyệt có ngừng khóa - và cuối cùng hiển thị đầu ra (hoàn chỉnh) của test.pl:

YEAH hello 2 there CMON
CMON hello 3 there YEAH
STEP hello 4 there NOW
STEP hello 5 there AGAIN

Tất nhiên, loại gỡ lỗi này có thể được thực hiện ngay cả khi không chạy máy chủ web - tuy nhiên, điều thú vị ở đây là chúng tôi hoàn toàn không chạm vào máy chủ web; chúng tôi kích hoạt thực thi "nguyên bản" (đối với CGI) từ trình duyệt web - và thay đổi duy nhất cần thiết trong chính tập lệnh CGI, là sự thay đổi của shebang (và tất nhiên, sự hiện diện của tập lệnh shebang wrapper, dưới dạng tệp thực thi trong cùng danh mục).

Vâng, hy vọng điều này sẽ giúp người - Tôi chắc chắn sẽ thích đã stumbled khi này, thay vì viết nó bản thân mình :)
Cheers!


5

Đối với tôi, tôi sử dụng log4perl . Nó khá hữu ích và dễ dàng.

use Log::Log4perl qw(:easy);

Log::Log4perl->easy_init( { level   => $DEBUG, file    => ">>d:\\tokyo.log" } );

my $logger = Log::Log4perl::get_logger();

$logger->debug("your log message");

1

Thành thật mà nói, bạn có thể làm tất cả những điều thú vị trên bài đăng này. RỒI, giải pháp đơn giản và chủ động nhất mà tôi tìm thấy là chỉ cần "in nó".

Trong ví dụ: (Mã bình thường)

`$somecommand`;

Để xem liệu nó có đang làm những gì tôi thực sự muốn nó làm hay không: (Sự cố khi chụp)

print "$somecommand";

1

Có lẽ cũng sẽ đáng nói là Perl sẽ luôn cho bạn biết lỗi xảy ra khi bạn thực thi tập lệnh Perl từ dòng lệnh. (Một phiên SSH chẳng hạn)

Tôi thường sẽ làm điều này nếu vẫn thất bại. Tôi sẽ SSH vào máy chủ và thực thi tập lệnh Perl theo cách thủ công. Ví dụ:

% perl myscript.cgi 

Nếu có vấn đề thì Perl sẽ cho bạn biết về nó. Phương pháp gỡ lỗi này loại bỏ bất kỳ sự cố nào liên quan đến quyền đối với tệp hoặc sự cố trình duyệt web hoặc máy chủ web.


Perl không phải lúc nào cũng cho bạn biết số dòng nơi xảy ra lỗi. Nó cho bạn biết số dòng nơi nó nhận ra có điều gì đó không ổn. Lỗi có thể đã xảy ra.
brian d foy

0

Bạn có thể chạy perl cgi-script trong terminal bằng lệnh dưới đây

 $ perl filename.cgi

Nó diễn giải mã và cung cấp kết quả bằng mã HTML. Nó sẽ báo lỗi nếu có.


1
Xin lỗi, lệnh $ perl -c filename.cgi xác thực cú pháp của mã và thông báo lỗi nếu có. Nó sẽ không cung cấp mã html của cgi.
D.Karthikeyan

Lời mời perl -c filenamethực sự sẽ chỉ kiểm tra cú pháp. Nhưng perl filenamekhông in đầu ra HTML. Tuy nhiên, không có gì đảm bảo rằng sẽ không có lỗi 500 CGI, nhưng đây là một thử nghiệm đầu tiên tốt.
Nagev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.