Swift - URLSessionUploadTask在将整个流写入请求主体

时间:2017-01-10 23:50:19

标签: swift swift3 nsurlsession nsurlsessionuploadtask

我想要实现的目标:

Swift 3.0 中,我目前正在尝试生成一个大型XML文件,我希望通过HTTP POST请求将其直接发送到网络服务器。因为这个XML文件可能会非常大,所以我不想将它完全存储在内存中,或者先将其写入磁盘,然后在将其发送到服务器时逐行读取。

我已经实现了生成XML文件的类,它可以写入OutputStream。这样,该流是指向磁盘上的文件,内存中的Data对象,还是(希望)指向HTTP POST请求的主体并不重要。

我打算做什么:

在搜索URLSessionStream类及其同谋的(有些稀缺的)Swift文档后,我决定使用URLSession.uploadTask(withStreamedRequest)任务。此请求需要通过其中一种委托方法传递InputStream

urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)

在此回调中,我使用InputStream绑定OutputStreamStream.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框架中我感到非常迷茫,并且花了我一天半的时间才能做到这一点,所以任何建议都非常感激。我会买任何能用这两杯啤酒帮助我的人!

提前感谢您的帮助!

编辑1:

正如@dgatwood所指出的,有些变量没有得到妥善保留。我做了以下更改,以确保他们这样做:

URLSession

1 个答案:

答案 0 :(得分:2)

在聊天中进行一些跟进后简短回答:

  • 写入的对象没有被保留,因此当它被释放时,它会释放流,然后关闭它。
  • 执行写入的对象,即使它正确检查了hasSpaceAvailable,也没有检测到短写入(因为可用空间少于正在写入的对象),因此数据在每次写入调用时都会丢失。
  • 写作的对象最后没有关闭流。

顺便提一下,这些是使用基于流的网络API时人们做错的规范事情。在使用相关的基础级套接字API时,我自己犯了类似的错误。

IMO,如果API只是缓冲一个对象,无论其长度如何都会更有意义,如果它仍然在套接字缓冲区中有空间,则发送空格可用消息。这不会要求对现有客户进行任何更改,并且会导致更少的麻烦...但我离题了。