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

超1MB POST请求浏览器提交被截断,Postman提交正常

问题概述

用JavaScript的fetch发送POST请求提交超过1MB的表单数据,后端通过Perl/CGI脚本将数据写入文件时出现以下问题:

  • Chrome/IE提交时,数据会在1MB处被截断,无法完整保存;
  • 用Postman提交相同的原始数据则可成功保存;
  • Postman和浏览器请求的Content-Length均显示正确长度;
  • 返回响应对比:Postman能返回完整的6MB数据+分隔符,浏览器仅返回1MB数据;
  • 提交略小于1MB的数据时,浏览器可正常上传保存;
  • 浏览器网络面板显示完整的6MB请求,但无法确认数据是否完整到达后端,未找到明确的限制配置。
现有代码

JavaScript 上传函数

async function serverSave(data, access) {
    // Data to send in the POST request
    const formData = new FormData();
    formData.append('access', access);
    formData.append('data', data);
  
    // URL endpoint to send the POST request to
    const url = 'http://www.mywebsite.com/cgi-bin/upload.pl';
    // Options for the fetch request
    const options = { method: 'POST', body: formData };
    
    // Send the POST request using fetch
    try{
        response = fetch(url, options);
        const result = await response.text();
        console.log('Response:', result);
    }
    catch {
        // Handle errors
        console.error('There was a problem saving to the server', error);
    };  
}

Perl CGI 处理脚本

#!/usr/bin/perl
use strict;
use warnings;

my $buffer = '';
if($ENV{CONTENT_LENGTH}) { read(STDIN,$buffer,$ENV{CONTENT_LENGTH}); }

my ($data_value) = $buffer =~ /name="data"\s*?\n\s*?\n(.+?)\n-{5}/s;
my ($access_value) = $buffer =~ /name="access"\s*?\n\s*?\n(.+?)\n-{5}/s;

$access_value =~ s/[\r\n]+$//;
$data_value =~ s/[\r\n]+$//;

my $fn = "../zfiles/".$access_value.".json";

open(FH, '>', $fn) or die $!;
print FH $data_value;
close(FH);

print "Content-type: text/plain\n\n";
print $buffer;
print "OK";
print $ENV{CONTENT_LENGTH};
问题根源
  1. Perl脚本的STDIN读取逻辑缺陷:
    直接使用read(STDIN, $buffer, $ENV{CONTENT_LENGTH})单次读取数据,在CGI环境下,当数据量较大时,系统会限制单次读取的缓冲区大小(通常为1MB),导致无法一次性读取完整的CONTENT_LENGTH字节数,最终$buffer只包含部分数据。
  2. 手动正则解析表单数据的风险:
    用(.+?)\n-{5}这种非贪婪匹配解析multipart/form-data,当$buffer被截断后,无法找到完整的分隔符-----,导致匹配到不完整的data_value。
  3. JavaScript代码的小疏漏:
    原代码中response = fetch(url, options)缺少await,会导致后续await response.text()处理的是未完成的Promise,虽然这不是本次数据截断的直接原因,但可能引发其他异步处理问题。
修复方案

1. 修复Perl的STDIN循环读取逻辑

替换单次read为循环读取,确保获取完整的请求数据:

my $buffer = '';
if ($ENV{CONTENT_LENGTH}) {
    my $remaining = $ENV{CONTENT_LENGTH};
    while ($remaining > 0) {
        my $bytes_read = read(STDIN, $buffer, $remaining, length($buffer));
        last unless defined $bytes_read; # 处理读取错误
        $remaining -= $bytes_read;
    }
}

2. 使用CGI.pm模块解析表单数据(推荐)

手动解析multipart/form-data极易出错,Perl自带的CGI.pm能正确处理表单数据,避免正则匹配的缺陷:

#!/usr/bin/perl
use strict;
use warnings;
use CGI;

my $cgi = CGI->new;
my $access_value = $cgi->param('access');
my $data_value = $cgi->param('data');

# 清理末尾的换行符
$access_value =~ s/[\r\n]+$// if defined $access_value;
$data_value =~ s/[\r\n]+$// if defined $data_value;

my $fn = "../zfiles/" . $access_value . ".json";

open(FH, '>', $fn) or die $!;
print FH $data_value;
close(FH);

print "Content-type: text/plain\n\n";
print $data_value; # 返回完整数据用于验证
print "OK";
print $ENV{CONTENT_LENGTH};

3. 修正JavaScript的异步处理

补全await并正确捕获错误参数:

async function serverSave(data, access) {
    const formData = new FormData();
    formData.append('access', access);
    formData.append('data', data);
  
    const url = 'http://www.mywebsite.com/cgi-bin/upload.pl';
    const options = { method: 'POST', body: formData };
    
    try {
        const response = await fetch(url, options);
        const result = await response.text();
        console.log('Response:', result);
    } catch (error) {
        console.error('There was a problem saving to the server', error);
    }  
}
验证步骤
  • 上传超过1MB的数据,检查后端生成的json文件是否完整;
  • 查看响应返回的内容是否与提交的数据一致;
  • 确认Content-Length数值与实际写入文件的大小匹配。

内容的提问来源于stack exchange,提问作者Chris ten Den

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:15:14