- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在 Swift 3.0 中,我目前正在尝试生成一个大型 XML 文件,我想通过 HTTP POST 请求将其直接发送到网络服务器。因为这个 XML 文件可能会变得非常大,所以我不想将它完全存储在内存中,或者先将其写入磁盘,然后在发送到服务器时再逐行读取。
我已经实现了生成 XML 文件的类,它可以写入 OutputStream
。这样,无论该流指向磁盘上的文件、内存中的 Data
对象,还是(希望)HTTP POST 请求的主体,都无关紧要。
在为 URLSession
和 Stream
类及其同伙搜索(有点稀缺)Swift 文档后,我决定使用 URLSession.uploadTask(withStreamedRequest)
任务。此请求需要通过委托(delegate)方法之一传递 InputStream
:
urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)
在此回调中,我使用 Stream.getBoundStreams()
绑定(bind)了一个 InputStream
和 OutputStream
,之后我传递了 OutputStream
到生成 XML 的类,并从委托(delegate)方法返回 InputStream
。因此,委托(delegate)方法如下所示:
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!)
}
有时,生成 XML 的类在将下一行写入 OutputStream
之前可能需要一些时间。如果这种情况发生的时间过长,InputStream
可能会读取太多内容,以至于它实际上会清除整个缓冲区。当这种情况发生时,URLSession
框架(或者可能是 URLSessionUploadTask
本身)认为请求现在已完成并“提交”或“完成”它。然而,这是一个猜测,因为我不确定这些类的内部工作原理(而且文档似乎对我帮助不大)。这会导致我的网络服务器收到不完整的 XML 文件并返回 500 Internal Server Error
。
有什么方法可以阻止请求提前完成?最好是,我想在 type.convert
调用的回调中“完成”输入流,因为我确信此时不会发生更多写入(并且 OutputStream
实际上是关闭的)。
这是解决我要解决的问题的正确方法吗?有没有什么办法可以直接与写入 HTTP 正文的流进行交互?我对这个 URLSession
框架感到很迷茫,我花了一天半的时间才走到这一步,所以非常感谢任何建议。我会请任何能帮我解决这个问题的人喝一两杯啤酒!
在此先感谢您的帮助!
正如@dgatwood 所指出的,一些变量没有正确保留。我已进行以下更改以确保它们确实如此:
var mInput: InputStream? = nil
var mOutput: OutputStream? = nil
var mConverter: DatabaseConverterXml? = nil
var mType: ConverterTypeSynchronization? = nil
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.
let bufferSize: Int = 1024
Stream.getBoundStreams(withBufferSize: bufferSize, inputStream: &mInput, outputStream: &mOutput)
//This part is not really important for you, it starts the generation of
//the XML, which is written directly to the output stream.
mConverter = DatabaseConverterXml(prettyPrint: false)
mType = ConverterTypeSynchronization(progressAlert: nil)
mType.convert(using: mConverter, writingTo: [Writable.Stream(mOutput!)])
{
successfull in
print("Conversion Complete! Successfull: \(successfull)" )
}
//The input stream is then handed over via the
//completion handler of the delegate method.
completionHandler(mInput!)
}
最佳答案
在聊天中进行一些跟进后的简短回答:
顺便说一句,这些几乎是人们在使用基于流的网络 API 时常犯的错误。在使用相关的基础级套接字 API 时,我自己也犯过类似的错误。
IMO,如果 API 只缓冲一个对象而不考虑其长度,然后在套接字缓冲区中仍有空间,则发送可用空间消息会更有意义。这不需要对现有客户端进行任何更改,并且会导致更少的麻烦……但我离题了。
关于Swift - URLSessionUploadTask 在将整个流写入请求正文之前完成请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41580500/
我想实现的目标: 在 Swift 3.0 中,我目前正在尝试生成一个大型 XML 文件,我想通过 HTTP POST 请求将其直接发送到网络服务器。因为这个 XML 文件可能会变得非常大,所以我不想将
我遇到了一个奇怪的问题,新创建的 URLSessionUploadTask 立即被取消。我不确定这是否是当前 Xcode 8 测试版的错误。 我怀疑这可能是一个错误,因为我将要发布的代码恰好运行一次。
我正在编写简单的处理程序,用于与服务器(当前为本地)上的 REST API 进行通信。到目前为止,从/向服务器下载和上传数据一切顺利。 我现在想要实现的是能够处理上传数据后服务器返回的JSON响应。这
我是一名优秀的程序员,十分优秀!