11

我想向 NSInputStream 添加三个“部分”:一个 NSString,另一个流的输出,然后是另一个 NSString。思路如下:

第一个和最后一个 NSString 表示 SOAP 请求的开始和结束,而流的输出是加载一个非常大的文件并将其编码为 Base64 字符串的结果。所以,最后我会让最终的 NSInputStream 保存整个 SOAP 请求,如下所示:

<soap开头> <Base64编码数据> <soap结尾>

我希望将整个请求保存在 NSInputStream 中的原因有两个:

  1. 我不会将非常大的数据文件加载到内存中
  2. 我认为这是强制以 HTTP 1.1 块发送最终请求的唯一方法(我需要这样做,因为否则,如果请求变得太大,服务器将不会接受它)。所以,我知道这样做:

    NSInputStream *dataStream = ....; 
    [request setHTTPBodyStream:dataStream];
    

确保请求将作为 HTTP 1.1 块发送,而不是作为一个巨大的原始 SOAP 请求发送。

所以,我想知道这是如何实现的——也就是说,我如何将事物“排队”到 NSInputStream 中?甚至可以做到吗?有替代方法吗?

仅供参考,在Java中可以按如下方式完成

 Vector<InputStream> streamVec = new Vector<InputStream>();
 BufferedInputStream fStream = new BufferedInputStream(fileData.getInputStream());
 Base64InputStream b64stream = new Base64InputStream(fStream, true);
 String[] SOAPBody = GenerateSOAPBody(fileInfo).split("CUT_HERE");  
 streamVec.add(new ByteArrayInputStream(SOAPBody[0].getBytes()));
 streamVec.add(b64stream);
 streamVec.add(new ByteArrayInputStream(SOAPBody[1].getBytes()));
 SequenceInputStream seqStream = new SequenceInputStream(streamVec.elements());

因为 Java 有这些对象可用,但是 Objective-c 中的 NSStreams 看起来像非常低级的对象并且很难使用。

注意:我完全重写了两天前提出的原始问题,因为我认为新的编辑更清楚地解释了问题所在。我希望它会帮助它更容易理解并回答

更新 2

到目前为止,这是我能够实现的目标:我没有尝试加入流,而是使用临时文件先写入 <soap beginning>,然后设置输入流以从文件中读取块,将每个块编码为 Base64 字符串并将其写入同一个临时文件,最后,当我的流关闭时,我将 <soap ending> 写入临时文件。然后我用这个文件的内容设置了另一个输入流,我将它传递给 NSMutableURLRequest:

        NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
        ...
        NSInputStream *dataStream = [NSInputStream inputStreamWithFileAtPath:_tempFilePath];
        [request setHTTPBodyStream:dataStream];

这确保了文件内容的 HTTP 1.1 分块传输。连接完成后,删除临时文件。

这似乎工作正常,但当然这是一个烦人的工作。我不想写一个临时文件,因为它本来可以由流处理(理想情况下。)如果有人还有更好的建议,请告诉我:)

更新 3

好的,另一个更新是为了。虽然我的文件写入似乎有效,但我现在遇到了一个意外问题,我的一些请求无法上传到服务器。具体来说,一切都按计划进行,我正在将临时文件的内容读入一个流,并将我的请求的 HTTP 主体设置为这个流,它开始按照我的意愿传输 HTTP 1.1 块 - 但对于一些一些数据包被丢弃并且最终请求 - 这是我的猜测 - 格式错误并因此失败的原因。我认为丢弃数据包的问题是随机的,因为我在较大的请求中观察到它 - 也就是说,这个问题有更多的机会出现 - 而我的较小的请求通常会很好。这当然是与该问题中的原始问题不同的问题。如果有人知道可能导致这种情况的原因,在 NSURLConnection 发送的分块 HTTP 1.1 请求期间丢弃的数据包

4

1 回答 1

0

您的解决方案是一个不错的选择,但您可以使用流来完成。这意味着子类NSInputStream化,这不是微不足道的,因为您需要实现一堆方法。

基本上,您的子类最初会返回标题字节,然后它将字节从“内部”流返回到文件内容,然后当它用完时返回页脚字节。这意味着要记录页眉和页脚的大小以及到目前为止已经处理了多少,但这不是一个大问题。

这里有一个创建子类的示例,它显示了您需要实现的棘手隐藏方法,以使流子类正常工作而不会引发异常。

于 2016-07-05T21:26:08.567 回答