You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写Perl的Result模块管理HTTP错误,求核心实现指导

Hey there, let's work through your Result module and error handling setup step by step. I see you're trying to build a Perl module to manage HTTP errors, so let's break down what's working, what can be improved, and how to integrate this cleanly with your App.pm code.


First: Refining the Result.pm Core Error Handling

Your current generateError function works, but it can be made more maintainable, flexible, and aligned with Perl OO best practices. Here's an optimized version with key improvements explained:

package Result;
use strict;
use warnings;
use Log::Log4perl;

# Initialize logger (assumes you've configured Log::Log4perl elsewhere in your app)
my $logger = Log::Log4perl->get_logger(__PACKAGE__);

sub new {
    my $class = shift;
    my %params = @_;

    # Validate required parameters to avoid invalid Result objects
    die "Missing required 'code' parameter for Result->new" unless exists $params{code};

    my $self = {
        code  => $params{code},
        value => $params{value}, # Optional: store context data like IDs, user info
    };

    bless $self, $class;
    return $self;
}

# Encapsulate internal state with accessors (avoids direct hash key access)
sub code {
    my $self = shift;
    if (@_) {
        $self->{code} = shift;
        $logger->debug("Updated Result HTTP code to " . $self->{code});
    }
    return $self->{code};
}

sub value {
    my $self = shift;
    $self->{value} = shift if @_;
    return $self->{value};
}

sub generateError {
    my $self = shift;
    my %params = @_;

    my $code = $self->code;
    # Replace messy elsif chains with a maintainable hash of error messages
    my %standard_messages = (
        200 => "Your request was executed successfully!",
        400 => "Bad request: Please verify your input and try again.",
        403 => "Access denied: You don't have permission to access this resource.",
        404 => "Resource not found: We couldn't locate what you're looking for.",
        500 => "Internal server error: Our team has been notified, please try again later.",
        504 => "Gateway timeout: Your request took too long to process, please retry."
    );

    # Allow custom message overrides for specific scenarios
    my $message = $params{custom_message} || $standard_messages{$code} 
        || "Unknown error code: $code";

    # Log based on error severity (errors = 4xx/5xx, success = 2xx)
    if ($code >= 400) {
        $logger->error("HTTP $code: $message" . ($self->value ? " | Context: " . Dumper($self->value) : ""));
    } else {
        $logger->info("HTTP $code: $message");
    }

    return $message;
}

1;

Key Improvements:

  • Encapsulation: Added accessor methods (code, value) instead of directly accessing $self->{code}. This makes future changes to the module's internal structure easier.
  • Maintainable Error Messages: Swapped the long elsif chain with a hash—adding new HTTP codes only requires a new hash entry, not more conditional logic.
  • Parameter Validation: The new method now checks for the required code parameter to prevent invalid Result objects.
  • Flexibility: Supports custom error messages via the custom_message parameter in generateError.
  • Better Logging: Uses your existing Log::Log4perl setup to log errors with context (if you provide value data like project IDs or user IDs).
  • Fixed Syntax: Corrected the missing semicolon in your original 404 error message.

Second: Integrating Result.pm with App.pm

Your App.pm currently redirects to error pages, but we can use the Result module to standardize error handling and add context. First, add use Result; at the top of App.pm, then update your template method:

sub template {
    my $self = shift;
    my $query = $self->query;
    my $id = $query->param('id');
    my $session = $self->param('session');
    my $profile = $session->param('profile');

    my $Project = Project->newFromId($id);
    if (!$Project or $Project eq 'NOT_FOUND') {
        # Create a 404 Result with context (project ID)
        my $error = Result->new(code => 404, value => { project_id => $id });
        my $error_msg = $error->generateError;
        
        # Option 1: Redirect to your existing notfound handler with the error message
        return $self->redirect("?rm=notfound&error=" . URI::Escape::uri_escape($error_msg));
        # Option 2: Render an error template directly with the Result object
        # return $self->processtmpl('error.tmpl', { error => $error });
    }

    if (!$profile->{'uid'} or $Project->{'userId'} != $profile->{'uid'}) {
        # Use 403 Forbidden (correct HTTP code for permission issues, not 404)
        my $error = Result->new(code => 403, value => { project_id => $id, user_id => $profile->{'uid'} });
        my $error_msg = $error->generateError(custom_message => "You don't have permission to view this project.");
        
        return $self->redirect("?rm=accessdenied&error=" . URI::Escape::uri_escape($error_msg));
    }

    # Rest of your existing code...
    my $mailContent = from_json($Project->{'mail'});
    my $templateContent = formatTemplate($Project->{'template'});
    my $infos = [
        {
            'ID' => $id,
            'TEMPLATE' => $templateContent,
            'MAILSUBJECT' => $mailContent->{'subject'},
            'MAILBODY' => $mailContent->{'body'}
        }
    ];

    if ($mailContent->{'type'} eq 'text') {
        $infos->[0]{'MAILTEXT'} = 1;
    } else {
        $infos->[0]{'MAILHTML'} = 1;
    }

    # Optional: Log the successful request with Result
    my $success = Result->new(code => 200, value => { project_id => $id });
    $success->generateError;

    return $self->processtmpl('template.tmpl', $infos);
}

Integration Notes:

  • Correct HTTP Codes: Replaced the incorrect 404 redirect for permission issues with a 403 Forbidden code—this aligns with HTTP standards and makes debugging easier.
  • Contextual Errors: Added value data (like project/user IDs) to Result objects, so your logs will have more detail about what went wrong.
  • Flexible Error Handling: Choose between redirecting to existing handlers (with escaped error messages) or rendering an error template directly with the Result object.

Bonus Best Practices

  • Structured Responses: If building an API, modify generateError to return JSON instead of plain text (e.g., return to_json({ code => $code, message => $message, details => $self->value })).
  • Exception Handling: Add a throw method to Result:
    sub throw {
        my $self = shift;
        die $self->generateError(@_);
    }
    
    Then use Try::Tiny in App.pm to catch exceptions cleanly.
  • Unit Tests: Write tests with Test::More to verify Result returns the correct messages for every HTTP code you support.

内容的提问来源于stack exchange,提问作者Maestro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:13:20