【发布时间】:2021-03-26 09:41:11
【问题描述】:
这是我用于上传文件的 REST API-
@api.route('/update_profile_picture', methods=['POST'])
def update_profile_picture():
if 'file' in request.files:
image_file = request.files['file']
else:
return jsonify({'response': None, 'error' : 'NO File found in request.'})
filename = secure_filename(image_file.filename)
image_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
image_file.save(image_path)
try:
current_user.image = filename
db.session.commit()
except Exception as e:
return jsonify({'response': None, 'error' : str(e)})
return jsonify({'response': ['{} profile picture update successful'.format(filename)], 'error': None})
上面的代码在我用邮递员测试时工作正常,但在邮递员中我可以设置一个文件对象。 但是,当我尝试从 iOS 应用程序上传时,它给了我错误-
NO File found in request
这是我上传图片的快速代码-
struct ImageFile {
let fileName : String
let data: Data
let mimeType: String
init?(withImage image: UIImage, andFileName fileName: String) {
self.mimeType = "image/jpeg"
self.fileName = fileName
guard let data = image.jpegData(compressionQuality: 1.0) else {
return nil
}
self.data = data
}
}
class FileLoadingManager{
static let sharedInstance = FileLoadingManager()
private init(){}
let utilityClaas = Utility()
func uploadFile(atURL urlString: String, image: ImageFile, completed:@escaping(Result<NetworkResponse<String>, NetworkError>)->()){
guard let url = URL(string: urlString) else{
return completed(.failure(.invalidURL))
}
var httpBody = Data()
let boundary = self.getBoundary()
let lineBreak = "\r\n"
let contentType = "multipart/form-data; boundary = --\(boundary)"
httpBody.append("--\(boundary + lineBreak)")
httpBody.append("Content-Disposition: form-data; name = \"file\"; \(lineBreak)")
httpBody.append("Content-Type: \(image.mimeType + lineBreak + lineBreak)")
httpBody.append(image.data)
httpBody.append(lineBreak)
httpBody.append("--\(boundary)--")
let requestManager = NetworkRequest(withURL: url, httpBody: httpBody, contentType: contentType, andMethod: "POST")
let urlRequest = requestManager.urlRequest()
let dataTask = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if let error = error as? NetworkError{
completed(.failure(error))
return
}
if let response = response as? HTTPURLResponse{
if response.statusCode < 200 || response.statusCode > 299{
completed(.failure(self.utilityClaas.getNetworkError(from: response)))
return
}
}
guard let responseData = data else{
completed(.failure(NetworkError.invalidData))
return
}
do{
let jsonResponse = try JSONDecoder().decode(NetworkResponse<String>.self, from: responseData)
completed(.success(jsonResponse))
}catch{
completed(.failure(NetworkError.decodingFailed))
}
}
dataTask.resume()
}
private func boundary()->String{
return "--\(NSUUID().uuidString)"
}
}
extension Data{
mutating func append(_ string: String) {
if let data = string.data(using: .utf8){
self.append(data)
}
}
}
这里还有 NetworkRequest 结构-
class NetworkRequest{
var url: URL
var httpBody: Data?
var httpMethod: String
var contentType = "application/json"
init(withURL url:URL, httpBody body:Data, contentType type:String?, andMethod method:String) {
self.url = url
self.httpBody = body
self.httpMethod = method
if let contentType = type{
self.contentType = contentType
}
}
func urlRequest()->URLRequest{
var request = URLRequest(url: self.url)
request.addValue(contentType, forHTTPHeaderField: "Content-Type")
request.httpBody = self.httpBody
request.httpMethod = self.httpMethod
return request
}
}
在ImageLoaderViewController中,选择一张图片发送上传。
class ImageLoaderViewController: UIViewController {
@IBOutlet weak var selectedImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func selectImage(){
if selectedImageView.image != nil{
selectedImageView.image = nil
}
let imagePicker = UIImagePickerController()
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
@IBAction func uploadImageToServer(){
if let image = imageFile{
DataProvider.sharedInstance.uploadPicture(image) { (msg, error) in
if let error = error{
print(error)
}
else{
print(msg!)
}
}
}
}
func completedWithImage(_ image: UIImage) -> Void {
imageFile = ImageFile(withImage: image, andFileName: "test")
}
}
extension ImageLoaderViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate{
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.originalImage] as? UIImage{
picker.dismiss(animated: true) {
self.selectedImageView.image = image
self.completedWithImage(image)
}
}
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
【问题讨论】:
-
嗯...这不是 Swift。您应该从问题中删除
[swift]标签。 -
"我正在尝试使用 URLSession。"你有 Swift 代码吗?你知道 POSTMAN 可以为你的请求生成 Swift 代码吗?不是漂亮的代码,但您可能会使用/获得灵感的代码?
-
跳转到错误的标签可能会令人沮丧..所以请删除 [swift]
-
我认为作者最终想要的是Swift代码,但没有表现出任何努力,只是用另一种语言显示他/她的服务器代码。
-
我需要一些帮助或资源提示,告诉我如何编写 iOS 客户端代码以使用 URLSession 发送图像。
标签: swift file-upload python-requests urlsession urlrequest