I am using URLSessionConfiguration.background and uploadTask to upload a file from an iOS app.
The upload session is configured in the following way:
let configuration = URLSessionConfiguration.background(withIdentifier: "com.mycompany.myapp.fileUploader")
configuration.isDiscretionary = false
configuration.allowsCellularAccess = true
uploadURLSession = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
and the request is:
request.httpMethod = "POST"
request.setValue("application/octect-stream", forHTTPHeaderField: "Content-Type")
let task = uploadURLSession.uploadTask(with: request, fromFile: fileURL)
I'd like to understand how to manage the error handling.
How the http errors 4xx or 5xx are handled by the URLSession.uploadTask?
How can I trigger the retrying on 5xx errors?
CodePudding user response:
Create the upload task like this:
let task = uploadSession?.uploadTask(with: request, fromFile: fileURL, completionHandler: { data, response, error in
if let error = error {
print("Upload error: \(error.localizedDescription)")
} else {
if let response = response as? HTTPURLResponse {
print("Response status code: \(response.statusCode)")
}
}
})
task?.resume()
you can handle errors and responsecode in the callback ☝️, alternatively
you can look at URLSessionTaskDelegate
and and URLSessionDataDelegate
for a fine-grained control over the upload task.
CodePudding user response:
URLSession.uploadTask does not handle the http server side errors. It handles retrying and errors only for client side or network issues.
The http status/error has to be retrieved from the task response casting it to an HTTPURLResponse.
Directly from the uploadTask call (not supported by background URLSession):
let task = uploadSession?.uploadTask(with: request, fromFile: fileURL, completionHandler: { data, response, error in
if let error = error {
print("Upload error:\(error)")
//Client side error
return
}
guard let res = response as? HTTPURLResponse else {
print("Upload completed with response:\(response.description ?? "undefined")")
//It should not happen at all
return
}
if (200...299).contains(res.statusCode) {
print("Upload completed successfully. Status code:\(res.statusCode)")
}
else if (400...499).contains(res.statusCode) {
print("Upload fatal issue. Status code:\(res.statusCode)")
//Fatal issue, do not retry the upload
}
else if (500...599).contains(res.statusCode) {
print("Upload issue. Status code:\(res.statusCode)")
//Schedules a new uploading task for the file
}
else {
print("Upload completed with status code:\(res.statusCode)")
}
})
or, if you are using a background URLSession, from the URLSessionTaskDelegate:
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let error = error {
print("Upload error:\(error)")
//Client side error
return
}
guard let res = task.response as? HTTPURLResponse else {
print("Upload completed with response:\(task.response?.description ?? "undefined")")
//It should not happen at all
return
}
if (200...299).contains(res.statusCode) {
print("Upload completed successfully. Status code:\(res.statusCode)")
}
else if (400...499).contains(res.statusCode) {
print("Upload fatal issue. Status code:\(res.statusCode)")
//Fatal issue, do not retry the upload
}
else if (500...599).contains(res.statusCode) {
print("Upload issue. Status code:\(res.statusCode)")
//Schedules a new uploading task for the file
}
else {
print("Upload completed with status code:\(res.statusCode)")
}
}