首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >iOS Swift应用编程接口POST请求因URLSession调用缓慢而重复

iOS Swift应用编程接口POST请求因URLSession调用缓慢而重复
EN

Stack Overflow用户
提问于 2021-06-11 05:56:40
回答 2查看 272关注 0票数 1

我有一个下载任务,首先调用REST API,服务器需要生成一个相当大的文件,这需要几分钟来生成,因为它是CPU和磁盘IO密集型的。客户机等待服务器使用它生成的文件的URL给出JSON响应。然后,在获得第一个结果后开始文件下载。

对于生成特别大的文件的调用,这会导致服务器响应非常慢,我看到的是我的代码没有启动的重复请求。

最初,在服务器端工作的人告诉我重复请求的事情。然后,我设置了一种检查网络流量的方法。这是通过设置连接到有线网络的Mac并启用网络共享和使用Proxyman来检查从iPhone到API服务器的流量来完成的。我在网络层看到同一个API请求的多个实例,但我的代码从未被通知过。

代码如下所示

代码语言:javascript
运行
复制
@objc class OfflineMapDownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate {
@objc func download(){     
    
    let config = URLSessionConfiguration.background(withIdentifier: "OfflineMapDownloadSession")
    config.timeoutIntervalForRequest = 500
    config.shouldUseExtendedBackgroundIdleMode = true
    config.sessionSendsLaunchEvents = true
  
    urlSession = URLSession(configuration: config, delegate: self, delegateQueue: nil)    
    getMapUrlsFromServer(bounds)
}


func getMapUrlsFromServer(){
    
    var urlString = "http://www.fake.com/DoMakeMap.php" 
    if let url = URL(string: urlString) {
        let request = NSMutableURLRequest(url: url)
        //...Real code sets up a JSON body in to params...
        request.httpBody = params.data(using: .utf8 )
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        request.timeoutInterval = 500
        urlSession?.configuration.timeoutIntervalForRequest = 500
        urlSession?.configuration.timeoutIntervalForResource = 500
        request.httpShouldUsePipelining = true
        let backgroundTask = urlSession?.downloadTask(with: request as URLRequest)
        backgroundTask?.countOfBytesClientExpectsToSend = Int64(params.lengthOfBytes(using: .utf8))
        backgroundTask?.countOfBytesClientExpectsToReceive = 1000
        backgroundTask?.taskDescription = "Map Url Download"
        backgroundTask?.resume()
    }
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {    
    if (downloadTask.taskDescription == "CTM1 Url Download") {
        do {
            let data = try Data(contentsOf: location, options: .mappedIfSafe)
            let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
            if let jsonResult = jsonResult as? Dictionary<String, AnyObject> {
                if let ctm1Url = jsonResult["CTM1Url"] as? String {
                    if let filesize = jsonResult["filesize"] as? Int {
                        currentDownload?.ctm1Url = URL(string: ctm1Url)
                        currentDownload?.ctm1FileSize = Int32(filesize)
                        if (Int32(filesize) == 0) {
                            postDownloadFailed()
                        } else {
                            startCtm1FileDownload(ctm1Url,filesize)
                        }
                    }
                }
            }
        } catch {
            postDownloadFailed()
        }
    }
}    

这个download类还有更多功能,因为一旦第一个api调用完成,它就会下载实际的文件。由于问题发生在代码执行之前,因此我没有将其包含在示例代码中。

Proxyman的日志显示API调用在(分钟:秒) 46:06、47:13、48:21、49:30、50:44、52:06、53:45发出

看起来该请求的重复时间间隔仅超过1分钟。

有一个API字段,我可以在其中放置任何值,它将由服务器回显给我。我在那里放了一个用CACurrentMediaTime()生成的时间戳,然后登录Proxyman,结果显示确实是同一个API调用,所以我的代码不可能被多次调用。看起来好像iOS网络层正在重新发出http请求,因为服务器需要很长时间才能响应。这最终会在服务器上造成问题,API也会失败。

任何帮助都将不胜感激。

EN

回答 2

Stack Overflow用户

发布于 2021-06-24 03:52:24

我认为问题出在使用URLSessionConfiguration.background(withIdentifier:)进行此api调用时。

使用此方法初始化一个配置对象,该对象适合在应用程序在后台运行时传输数据文件。使用此对象配置的会话将传输控制权移交给系统,系统在单独的进程中处理传输。在iOS中,此配置使传输即使在应用本身被挂起或终止时也可以继续。

因此,问题在于,由于这种错误的API使用,系统正在不必要地重试您的请求。

以下是我的建议-

  1. 使用默认会话配置(而不是启动此长作业的此job_id调用,没有客户端在此作业上的等待,一旦此作业完成,从服务器端向客户端返回一个job_id,现在可以每X秒使用该api值轮询服务器以了解作业的状态,如果需要,甚至可以在客户端显示进度。当作业完成时,
  2. ,客户端下次轮询,它获取这个大file.
  3. Download文件的下载URL (根据您的喜好使用默认/后台会话配置)。
票数 2
EN

Stack Overflow用户

发布于 2021-06-28 01:16:06

这听起来很像TCP重传。如果客户端发送TCP数据段,而服务器在短时间内未确认收到,则客户端假定数据段未到达目的地,然后再次发送数据段。这是一种比URLSession低得多的机制。

这个API使用的HTTP服务器应用程序也有可能(比如Apache、IIS、LigHTTPd、nginx等)。被配置为使用响应数据进行确认,以节省打包和成帧开销。如果是这样,并且如果响应数据花费的时间超过客户端的TCP重新传输超时,您将得到此行为。

您是否有连接的数据包捕获?如果没有,请尝试使用tcpdump收集一个并在Wireshark中查看。如果我是对的,您将看到多个请求,并且它们都具有相同的序列号。

至于如何解决它,如果这是问题,我不确定。服务器应在收到请求后立即进行确认。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67928903

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档