当前位置: 首页 > news >正文

Delphi - IndyHttpServer接收上传文件

我使用delphi12CE+Indy中的idhttpserver接收post上来的图片,代码如下:

// 处理 POST 请求 
if SameText(ARequestInfo.Command, 'POST') and SameText(ARequestInfo.Document, '/upload') then 
begin if ARequestInfo.PostStream <> nil then begin outPath := TPath.Combine(FUploadDir, FormatDateTime('yyyymmdd_hhnnss_zzz',    Now).Replace('.', '') + '.jpg'); FileStream := TFileStream.Create(outPath, fmCreate); ARequestInfo.PostStream.Position := 0; FileStream.CopyFrom(ARequestInfo.PostStream, ARequestInfo.PostStream.Size); { Copy 流 } FileStream.Free; end; 
end;

可以接收,但是接收的图片文件都无法打开,使用NotePad++打开发现图片文件是这样的:

------WebKitFormBoundarybBNrZRN79bc6VhED Content-Disposition: form-data; name="name" all ------WebKitFormBoundarybBNrZRN79bc6VhED Content-Disposition: form-data; name="file"; filename="th_d6bee6de9e633c8618fab537b2ae3b3chd_042427.jpg" Content-Type: image/jpeg ??JFIF ?C

这是文件头,文件尾部还有:

------WebKitFormBoundarybBNrZRN79bc6VhED--

似乎是除了图片文件数据外头部和尾部还有其他的东西,如何解决这个问题呢?

经过分析,现在的 POST 请求是 multipart/form-data,而上面代码直接把 ARequestInfo.PostStream 整个保存成文件了,导致文件里面不仅有图片二进制,还包含了表单的边界(boundary)、Content-Disposition、Content-Type 等文本信息。
所以图片打不开是因为数据污染了。

Indy 的 TIdHTTPServer 在处理 multipart/form-data 时,并不会自动帮你分离文件,需要你手动解析表单。

解决方法是直接用 Indy 的 TIdMultiPartFormDataStream + ARequestInfo.RawHeaders 手动提取,下面是一个 Delphi12 CE 可运行的示例代码:
 

function ExtractFileFromRequest(ARequestInfo: TIdHTTPRequestInfo;out AFileName: string): TMemoryStream;
varLBoundary, LBoundaryMarker: string;LContent: TBytes;LContentStr, HeaderStr: string;PartStart, PartEnd, HeaderEnd: Integer;
beginResult := nil;AFileName := '';if not Assigned(ARequestInfo.PostStream) thenExit;// boundaryLBoundary := ARequestInfo.RawHeaders.Values['Content-Type'];if LBoundary = '' then Exit;LBoundary := Copy(LBoundary, Pos('boundary=', LBoundary) + 9, MaxInt);if LBoundary = '' then Exit;LBoundaryMarker := '--' + LBoundary;// 读取全部内容SetLength(LContent, ARequestInfo.PostStream.Size);ARequestInfo.PostStream.Position := 0;ARequestInfo.PostStream.ReadBuffer(LContent[0], Length(LContent));LContentStr := TEncoding.ANSI.GetString(LContent);// 遍历所有 partPartStart := Pos(LBoundaryMarker, LContentStr);while PartStart > 0 dobegin// 找 header 结束HeaderEnd := Pos(#13#10#13#10, LContentStr, PartStart);if HeaderEnd = 0 then Break;HeaderStr := Copy(LContentStr, PartStart, HeaderEnd - PartStart);if ContainsText(HeaderStr, 'filename="') thenbegin// 文件名AFileName := Copy(HeaderStr, Pos('filename="', HeaderStr) + 10, MaxInt);AFileName := Copy(AFileName, 1, Pos('"', AFileName) - 1);// 文件起点Inc(HeaderEnd, 4);// 找下一个 boundaryPartEnd := Pos(LBoundaryMarker, LContentStr, HeaderEnd);if PartEnd = 0 then Break;// ⚠️ 精确剔除 boundary 前的换行while (PartEnd > HeaderEnd) and((LContent[PartEnd - 2] = 13) or (LContent[PartEnd - 2] = 10)) doDec(PartEnd);// 复制二进制Result := TMemoryStream.Create;Result.WriteBuffer(LContent[HeaderEnd - 1], PartEnd - HeaderEnd + 1);Result.Position := 0;Exit;end;// 下一个 partPartStart := Pos(LBoundaryMarker, LContentStr, HeaderEnd);end;
end;

我把经过测试可以正常运行的代码封装到了一个单元中,下面是下载地址:

源代码下载


文章转载自:

http://SfeNLBgm.mhmsn.cn
http://0UixeyQQ.mhmsn.cn
http://1akgL58r.mhmsn.cn
http://D7wtfMVd.mhmsn.cn
http://lb9XuNl5.mhmsn.cn
http://8OEwHw0p.mhmsn.cn
http://BhjxqDH0.mhmsn.cn
http://MLypTFyz.mhmsn.cn
http://CdjxgOe5.mhmsn.cn
http://8ItYXHI5.mhmsn.cn
http://fLmxMVn8.mhmsn.cn
http://59pw57y5.mhmsn.cn
http://TuuNhlGm.mhmsn.cn
http://TwbuxIvh.mhmsn.cn
http://r4w4yM2T.mhmsn.cn
http://X5dPqa0K.mhmsn.cn
http://yHwoQWVH.mhmsn.cn
http://VMKUXr3Q.mhmsn.cn
http://pmVIhsAB.mhmsn.cn
http://4we6XBRG.mhmsn.cn
http://7gFPPJgn.mhmsn.cn
http://SfqjhO6o.mhmsn.cn
http://kekC9DJv.mhmsn.cn
http://yjV5EMUs.mhmsn.cn
http://k6a1uoAP.mhmsn.cn
http://dBMj9nuY.mhmsn.cn
http://X2nT03IK.mhmsn.cn
http://D1gNS516.mhmsn.cn
http://YhSmEDNk.mhmsn.cn
http://pkfRmScc.mhmsn.cn
http://www.dtcms.com/a/382878.html

相关文章:

  • 1.linux环境配置+ssh远程连接vscode调试(问题:无法联网,无法共享粘贴板,不满足运行vscode服务器的先决条件)
  • unity导入blender动画
  • 【杂谈】-备份革命:解锁AI时代的“死数据“金矿
  • npm 发布流程——从创建组件到发布到 npm 仓库
  • 单变量单步时序预测 | TCN-GRU时间卷积神经网络结合门控循环单元
  • 分布式协议与算法实战-理论篇
  • 《sklearn机器学习——数据预处理》生成多项式特征
  • XLua教程之入门篇
  • java学习笔记----标识符与变量
  • C7.1:谐振和调谐的含义
  • 代码随想录学习(一)——数组理论基础
  • Windows 平台上基于 MCP 构建“文心一言+彩云天气”服务实战
  • leetcode38(二叉树的最大深度)
  • PyTorch实战(7)——循环神经网络
  • 【LeetCode hot100|Week2】滑动窗口,子串
  • Web与Nginx网站服务(改)
  • Qt Designer与事件处理
  • 347. 前 K 个高频元素
  • Qt之快捷键、事件处理、自定义按键——完成记事本项目
  • 【微服务】SpringBoot 整合Kafka 项目实战操作详解
  • spring-kafka消费异常处理
  • 长城杯2025
  • Android BLE 蓝牙扫描完全指南:使用 RxAndroidBle框架
  • CKS-CN 考试知识点分享(3)---Dockerfile 安全最佳实践
  • 新一代控制理论框架:人机环境系统控制论
  • easyPoi实现动表头Excel的导入和导出
  • 【Zephyr电源与功耗专题】13_PMU电源驱动介绍
  • Coze源码分析-资源库-创建知识库-后端源码-应用/领域/数据访问
  • React Server Components (RSC) 与 App Router 简介:Next.js 的未来范式
  • 状态机SMACH相关教程介绍与应用案例分析——机器人操作进阶系列之一