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

使用Mojo::UserAgent解析字符串重建请求事务失败的问题排查

问题与解决方案

问题背景

我的目标是:

  • 使用Mojo::UserAgent手动创建有效的请求事务
  • 事务验证通过后,使用$tx->req->to_string将请求转存至文本文件
  • 通过解析文件内容重建新事务以实现复用

复用程序代码

use Mojo::Util qw/dumper/;
use Mojo::File qw/path/;
use Mojo::UserAgent;
use Mojo::Message::Request;
use Mojo::Transaction::HTTP;

my $req_string = path($ARGV[0])->slurp;

my $ua = Mojo::UserAgent->new;
my $tx = Mojo::Transaction::HTTP->new;

$tx->req->parse($req_string);

print dumper $tx->req; # 输出看起来是有效的Mojo::Message::Request对象

$tx = $ua->start($tx);
# 执行失败,报错:Can't call method "server" on an undefined value at /home/me/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2/Mojo/Server/Daemon.pm line 55.

print dumper $tx->res->body;

报错信息

Can't call method "server" on an undefined value at /home/me/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2/Mojo/Server/Daemon.pm line 55.

简化复现代码

use Mojo::UserAgent;
    
my $ua = Mojo::UserAgent->new;
my $tx = Mojo::Transaction::HTTP->new;

# 事务定义代码

$tx = $ua->start($tx);
print $tx->res->body; # 执行成功!

my $txt = $tx->req->to_string;

$tx = Mojo::Transaction::HTTP->new;
$tx->req->parse($txt);
$tx = $ua->start($tx); # 执行失败!
print $tx->res->body;

问题原因

$tx->req->to_string生成的是HTTP请求报文的原始内容,这部分内容里不包含请求的目标主机和完整URL——因为HTTP报文本身只包含路径、头部和正文,目标服务器地址是在建立TCP连接时单独指定的,不属于报文内容。

当你通过$tx->req->parse($txt)重建请求时,事务的req对象缺少了目标URL的主机信息,Mojo::UserAgent不知道该向哪个服务器发送请求,因此触发了报错。

解决方法

核心是在保存请求时,同时记录请求的完整URL,重建时补全这部分信息。

1. 修改保存逻辑(同时保存URL和请求报文)

# 原成功请求后,同时保存URL和请求字符串
my $successful_tx = $ua->start($tx);
my $req_string = $successful_tx->req->to_string;
my $target_url = $successful_tx->req->url->to_string;

# 将URL和请求报文用分隔符区分后写入文件
path('saved_request.txt')->spurt("$target_url\n---\n$req_string");

2. 修改重建逻辑(先补全URL再解析报文)

my $content = path($ARGV[0])->slurp;
# 拆分保存的URL和请求报文
my ($target_url, $req_string) = split /\n---\n/, $content, 2;

my $ua = Mojo::UserAgent->new;
my $tx = Mojo::Transaction::HTTP->new;

# 先设置目标URL,再解析请求报文
$tx->req->url->parse($target_url);
$tx->req->parse($req_string);

# 发起请求
$tx = $ua->start($tx);
print dumper $tx->res->body;

如果已经明确知道目标URL,也可以直接在重建时手动设置,不用额外保存:

my $req_string = path($ARGV[0])->slurp;
my $ua = Mojo::UserAgent->new;
my $tx = Mojo::Transaction::HTTP->new;

# 直接设置目标URL
$tx->req->url->parse('https://your-target-server.com/path');
$tx->req->parse($req_string);

$tx = $ua->start($tx);
print dumper $tx->res->body;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:28:16