Mojolicious登录后如何通过POST跳转并传递大量JSON数据?
解决Mojolicious(Lite)登录后传大量JSON到共享路由的问题
方案一:会话暂存数据(推荐)
利用Mojolicious的会话机制暂存大量JSON,登录后通过redirect_to跳转到目标路由,路由根据请求来源(AJAX POST/跳转GET)分别从请求体或会话读取数据。
代码示例
use Mojolicious::Lite -signatures; # 会话配置:如果数据超过4KB(Cookie默认上限),需配置服务器端存储(如Redis) app->secrets(['your_secure_secret_key']); app->sessions->default_expiration(3600); # 会话有效期1小时 # 登录路由 post '/login' => sub ($c) { # 模拟登录验证通过,生成大量JSON数据 my $large_json_data = { user => { id => 123, username => 'test_user' }, metrics => [ map { { category => "cat$_", value => rand(1000) } } 1..200 ], settings => { theme => 'dark', notifications => 1 } }; # 将数据存入会话,跳转后即可读取 $c->session->{target_data} = $large_json_data; # 重定向到命名路由 return $c->redirect_to('target_route'); }; # 目标路由:同时支持AJAX POST和跳转GET get '/target' => sub ($c) { my $data; # 区分请求类型 if ($c->req->method eq 'POST' && $c->req->is_xhr) { # AJAX POST请求:从请求体读取JSON $data = $c->req->json; } else { # 登录跳转的GET请求:从会话读取数据,读取后删除避免重复使用 $data = delete $c->session->{target_data}; # 处理未登录直接访问的情况 return $c->redirect_to('/login') unless $data; } # 渲染页面,传递数据到模板 $c->render(template => 'target', data => $data); } => 'target_route'; # 复用GET路由的逻辑处理POST请求 post '/target' => sub ($c) { $c->forward('target_route'); }; app->start;
注意事项
- 默认会话存储在Cookie中,上限约4KB,若JSON数据更大,需配置服务器端存储(如Redis):
use Mojo::Redis; my $redis = Mojo::Redis->new('redis://localhost:6379/'); app->sessions->store(Mojo::Session::Store::Redis->new(redis => $redis));
方案二:自动提交表单(无会话依赖)
若不想使用会话,可在登录成功后渲染一个自动提交的隐藏表单,将JSON数据嵌入表单字段,自动POST到目标路由。
代码示例
登录路由:
post '/login' => sub ($c) { my $large_json_data = { ... }; # 大量JSON数据 # 渲染自动提交的表单页面 $c->render(template => 'auto_post', data => $large_json_data); };
自动提交模板templates/auto_post.html.ep:
<form id="auto-submit-form" method="POST" action="<%= url_for('target_route') %>"> <textarea name="json_data" style="display: none"><%= to_json $data %></textarea> </form> <script> // 页面加载后自动提交表单 window.onload = () => document.getElementById('auto-submit-form').submit(); </script>
目标路由处理:
post '/target' => sub ($c) { my $data; if ($c->req->is_xhr) { # AJAX请求直接读取JSON $data = $c->req->json; } else { # 表单提交读取JSON字符串并解码 $data = $c->app->json->decode($c->req->param('json_data')); } $c->render(template => 'target', data => $data); } => 'target_route';
不推荐:proxy->post_p代理请求
你尝试的代理请求方式确实繁琐,原因包括:
- 需手动处理内部请求的会话、CSRF令牌等上下文信息,容易出错;
- 服务器内部额外发起一次请求,增加性能开销;
- 若目标路由需区分响应格式(页面/JSON),还要额外处理请求头判断,逻辑冗余。
除非有特殊业务需求,否则不建议使用该方式。
内容的提问来源于stack exchange,提问作者bliako
相关产品推荐
相关产品推荐

