2

我已经使用 Delphi XE2 构建了一个 DataSnap REST 服务器,并添加了一个用于通过 TStream 上传文件的服务器方法:

function TServerMethods.updateUploadFile(sFilename: string; UploadStream: TStream): string;

我希望能够从许多不同的客户端(Android、iOS 等)调用它,并且我一直在使用各种 REST 客户端(例如 Postman(Chrome 插件))测试该方法。但是到目前为止,我无法让它接受 HTTP POST 正文的内容。每当我发送 POST 命令时,我总是得到以下响应:

{"error":"Message content is not a valid JSON value."}

我尝试过使用各种不同的“内容类型”设置,但似乎没有任何效果。看起来好像 DataSnap 坚持内容是 JSON?我尝试将一些有效的 JSON 粘贴到内容区域,但这也给出了相同的错误响应。

有没有人成功使用 TStream 作为 DataSnap 服务器方法的输入参数?我应该以另一种方式做吗?我已经多次使用TStream作为下载文件的输出参数,效果很好,这是我第一次尝试上传。

更新

我制作了一个快速的 Delphi DataSnap 客户端来测试 uploadFile 服务器方法,这一切都很好。然后我使用 Fiddler 检查 Delphi 客户端用于在内容正文中发送 TStream 的 POST 命令,并注意到它是一个整数(字节)的 JSON 数组,例如[37,80,68,70,45,49,46,51,13,10]。所以我可以看到我可以在 POST 之前修改我的 Android/iOS 客户端以将二进制数据转换为这种字节数组格式,但这是我可以做到的开销。如果 DataSnap 在 TStream 是返回参数时流式传输原始二进制文件,为什么它不能将原始二进制文件作为输入参数传输?

4

1 回答 1

4

似乎在 POST 命令中将内容数据添加到请求正文时,DataSnap 服务器坚持认为该数据始终为 JSON。这就是为什么当使用 TStream 作为输入参数时,Delphi DataSnap 客户端将流数据转换为整数(字节)的 JSON 数组。这种格式的大小效率非常低,因为每个字节最多 3 位数字,加上逗号,上传的数据大小可以增长多达 4 倍。

因此,我所做的是对数据进行编码以在 Base64 中上传。我的服务器方法现在看起来像这样:

function TServerMethods.updateUploadFile(sFilename: string; Base64Data: TJSONObject): string;

请注意,我将 Base64 字符串包装在 TJSONObject 中。这是因为如果您只指定 String 类型,Delphi DataSnap 客户端将使用 GET 调用该方法并尝试将整个 Base64 字符串放入 URL 路径中,从而导致“正常关闭连接”错误。使用 TJSONObject 会强制 DataSnap 使用 POST 并将数据放入内容正文中。传递的 JSON 对象是一对对象:

{"UploadedData":"JVBERi0xLjMNCiXi48B5SiWGTK3PaY.........."}

这样上传数据的大小要小得多,传输速度更快。我仍然希望能够在内容正文中流式传输原始数据,但 DataSnap 不允许这样做。

于 2013-08-09T08:13:20.423 回答