在 Swift 3.0 中,我目前正在尝试生成一个大型XML文件,我希望通过HTTP POST请求将其直接发送到网络服务器。因为这个XML文件可能会非常大,所以我不想将它完全存储在内存中,或者先将其写入磁盘,然后在将其发送到服务器时逐行读取。
我已经实现了生成XML文件的类,它可以写入OutputStream
。这样,该流是指向磁盘上的文件,内存中的Data
对象,还是(希望)指向HTTP POST请求的主体并不重要。
在搜索URLSession
和Stream
类及其同谋的(有些稀缺的)Swift文档后,我决定使用URLSession.uploadTask(withStreamedRequest)
任务。此请求需要通过其中一种委托方法传递InputStream
:
urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)
在此回调中,我使用InputStream
绑定OutputStream
和Stream.getBoundStreams()
,之后我将OutputStream
传递给生成XML的类并返回{{ 1}}来自委托方法。委托方法因此如下所示:
InputStream
有时,生成XML的类可能需要一段时间才能将下一行写入func urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)
{
//Create the input and output stream and bind them, so that what the
//output stream writes ends up in the buffer of the input stream.
var input: InputStream? = nil
var output: OutputStream? = nil
let bufferSize: Int = 1024
Stream.getBoundStreams(withBufferSize: bufferSize, inputStream: &input, outputStream: &output)
//This part is not really important for you, it starts the generation of
//the XML, which is written directly to the output stream.
let converter = DatabaseConverterXml(prettyPrint: false)
let type = ConverterTypeSynchronization(progressAlert: nil)
type.convert(using: converter, writingTo: [Writable.Stream(output!)])
{
successfull in
print("Conversion Complete! Successfull: \(successfull)" )
}
//The input stream is then handed over via the
//completion handler of the delegate method.
completionHandler(input!)
}
。如果这种情况发生的时间过长,OutputStream
可能会读得太多,以至于它实际上清除了整个缓冲区。当发生这种情况时,InputStream
框架(或者可能是URLSession
本身)认为请求现在已经完成并且提交了#34;或者"敲定"它。然而,这是一个猜测,因为我不确定这些课程的内部运作方式(并且文档似乎对我没什么帮助)。这会导致我的网络服务器收到不完整的XML文件并返回URLSessionUploadTask
。
有什么方法可以阻止我们提前完成请求吗?最好,我想"敲定" 500 Internal Server Error
调用回调中的输入流,因为我当时肯定知道不会再发生写入(并且type.convert
实际上已关闭)。
这是解决我想要解决的问题的正确方法吗?有没有什么方法可以直接与写入HTTP正文的流进行交互?在这个OutputStream
框架中我感到非常迷茫,并且花了我一天半的时间才能做到这一点,所以任何建议都非常感激。我会买任何能用这两杯啤酒帮助我的人!
提前感谢您的帮助!
正如@dgatwood所指出的,有些变量没有得到妥善保留。我做了以下更改,以确保他们这样做:
URLSession
答案 0 :(得分:2)
在聊天中进行一些跟进后简短回答:
顺便提一下,这些是使用基于流的网络API时人们做错的规范事情。在使用相关的基础级套接字API时,我自己犯了类似的错误。
IMO,如果API只是缓冲一个对象,无论其长度如何都会更有意义,如果它仍然在套接字缓冲区中有空间,则发送空格可用消息。这不会要求对现有客户进行任何更改,并且会导致更少的麻烦...但我离题了。