我使用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]
。所以我可以看到我可以修改我的Android / iOS客户端,在POST之前将二进制数据转换为这种字节数组格式,但这是我无法做到的开销。如果在TStream是返回参数时DataSnap流式传输原始二进制文件,为什么它不能将原始二进制文件作为输入参数进行流式处理?
答案 0 :(得分:3)
似乎在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路径中,从而导致“Connection Closed Gracefully”错误。使用TJSONObject强制DataSnap使用POST并将数据放入内容正文中。传递的JSON对象是一对对象:
{"UploadedData":"JVBERi0xLjMNCiXi48B5SiWGTK3PaY.........."}
这样,上传的数据大小更小,传输速度更快。我仍然希望能够在内容体中传输原始数据,但DataSnap不允许这样做。