2016-02-22 11 views
6

परिदृश्य:स्विफ्ट अलामोफायर फ़ाइल हस्ताक्षरित अनुरोध के साथ अपलोड करें: प्राधिकरण शीर्षलेख कैसे भेजें?

  • iPhone आईओएस 8 अनुप्रयोग
  • प्रवेश प्रयोक्ता एप्लिकेशन पहले से ही Alamofire का उपयोग करता बैकएंड एपीआई के लिए अनुबंधित किया अनुरोध करने के लिए एक प्रोफ़ाइल तस्वीर

अपलोड कर देगा। वास्तव में सरल: ऐप हस्ताक्षरित होने के अनुरोध के लिए तीन विशिष्ट HTTP शीर्षलेख (Authorization, X-Api-Key और timestamp) भेजता है। Alamofire.request पर कॉल करना headers पैरामीटर के रूप में भेजना आसान है, इसलिए यह खूबसूरती से काम कर रहा है।

अब उपयोगकर्ताओं को अपलोड करने की आवश्यकता है उनकी प्रोफ़ाइल तस्वीर। चूंकि उपयोगकर्ता पहले से ही ऐप में लॉग इन है, बैकएंड एपीआई यह जान लेगा कि कौन सा उपयोगकर्ता चित्र हस्ताक्षरित अनुरोध द्वारा चित्र भेज रहा है - और यह मुश्किल हिस्सा है जो मैं पिछले कुछ घंटों से संघर्ष कर रहा हूं। Alamofire.upload.request से पूरी तरह से अलग पैरामीटर स्वीकार करता है, इसलिए मैं फ़ाइल अपलोड करते समय हेडर भेजने का तरीका नहीं समझ सकता।

पुराने Alamofire.Manager.session.configuration.HTTPAdditionalHeaders का प्रयास किया, लेकिन यह no longer supported है। फाइल अपलोड के टन कोड उदाहरण मिले, कोई भी कस्टम हेडर भेजने पर विचार नहीं करता है।

Alamofire.upload विधि का उपयोग करते समय मैं कस्टम हेडर कैसे भेज सकता हूं?

typealias requestDataType = [String:AnyObject] 
private func signRequest(data: requestDataType) -> [String:String] { 
    var headers = [String:String]() 

    var authString = "" 
    var signatureHeaders = "" 

    // Iterates over SORTED data dictionary to build headers 
    for (k,v) in (data.sort{$0.0 < $1.0}) { 
     if !authString.isEmpty { 
      authString += "\n" 
      signatureHeaders += " " 
     } 
     authString += "\(k): \(v)" 
     signatureHeaders += "\(k)" 
     headers[k] = "\(v)" 
    } 

    let userApiKey = _loggedInUser!["api_key"].string! 
    let signature = authString.sha256(_loggedInUser!["api_secret"].string!) 

    headers["X-Api-Key"] = userApiKey 
    headers["Authorization"] = "Signature headers=\"\(signatureHeaders)\",keyId=\"\(userApiKey)\",algorithm=\"hmac-sha256\",signature=\"\(signature)\"" 

    return headers 
} 

func uploadProfilePicture(photo: UIImage, callback: apiCallback){ 
    guard let userId = _loggedInUser?["pk"].int else { 
     callback(Response(success: false, responseMessage: "User not logged in")) 
     return 
    } 

    let requestData: requestDataType = ["timestamp": "\(Int(NSDate().timeIntervalSince1970))"] 

    let aManager = Manager.sharedInstance 
    print(self.signRequest(requestData)) // Prints correct headers (Authorization, X-Api-Key, timestamp) 
    aManager.session.configuration.HTTPAdditionalHeaders = self.signRequest(requestData) 
    print(aManager.session.configuration.HTTPAdditionalHeaders) // Prints default headers, completely ignoring my custom headers 

    aManager.upload(.POST, "\(_apiBaseUrl)profiles/\(userId)/photo/", multipartFormData: { multipartFormData in 
     if let imageData = UIImageJPEGRepresentation(photo, 0.8) { 
      multipartFormData.appendBodyPart(data: imageData, name: "upload", fileName: "userphoto.jpg", mimeType: "image/jpeg") 
     } 

     for (key, value) in requestData { 
      multipartFormData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key) 
     } 

     }, encodingCompletion: { 
      encodingResult in 

      debugPrint(encodingResult) 
    }) 
} 

अनुरोधों के माध्यम से अनुरोध किया जाता है। बैकएंड लॉग में मैं अनुरोध देख सकता हूं कि HTTP 403 लौटाया गया अनुरोध - अधिकृत नहीं है क्योंकि अनुरोध पर हस्ताक्षर करना संभव नहीं था। अनुरोध हेडर प्रिंट करना, सर्वर द्वारा कोई कस्टम ऑथ हेडर प्राप्त नहीं हुए थे।

+0

जोड़े कम से कम 'signRequest' विधि –

+0

@DavidBerry के लिए प्रोटोटाइप अपडेट किया गया। – mathielo

उत्तर

2

init से पहले, मैं इस प्रकार के कार्यों के दौरान एक मुफ्त टूल (क्रोम ऐप) बहुत उपयोगी साझा करना चाहता हूं: DHC Rest Client: इस टूल के साथ आप यह सत्यापित कर सकते हैं कि आपके पैरामीटर, हेडर और आपकी अपलोड फाइलें आपके अनुरोध के प्रकार के साथ काम करती हैं या नहीं सर्वर बनाना चाहते हैं।

तो, स्विफ्ट 2.x और Alamofire 3.x के साथ इस काम:

let headers = [ 
       "Content-Type": "application/zip", 
       "X-Api-Key": userApiKey, 
       ...whatever you need on headers.. 
      ] 

तो, मान आप एक ज़िप फ़ाइल भेजना चाहिए:

सबसे पहले अपने हेडर तैयार और प्रतिक्रिया एक टेक्स्ट/एचटीएमएल प्रतिक्रिया प्रकार (सफलता या त्रुटि के साथ एक साधारण स्ट्रिंग) होगी:

let filePath: String! = "/Users/admin.../Documents/myZipFile.zip" 
var zipData: NSData! = NSData() 
do { 
    zipData = try NSData(contentsOfFile: filePath, options: NSDataReadingOptions.DataReadingMappedIfSafe) 
} catch { 
    print("- error during get nsdata from zip file\(error)") 
} 
let url :String! = String(format:"...myUrl?key1=%@&key2=%@",value1,value2) 
Alamofire.upload(.POST, url, headers: headers, data: zipData) 
       .responseString { response in 
      if response.result.isSuccess { 
        let responseValue = response.result.value 
        print("Response value is: \(responseValue)") 
      } else { 
       var statusCode = 0 
       if (response.response != nil) { 
        statusCode = (response.response?.statusCode)! 
       } 
       print("Error: \(response.result.error!) with statusCode: \(statusCode)") 
      } 

यही सब है, लेकिन आप का उपयोग करने के multipartformdata आप इसे हेडर के माध्यम से अपने हेडर गुजर कर सकते हैं के साथ शब्दकोश चाहते हैं:

.upload (< # टी ## विधि: विधि ## विधि #>, < # टी # #URLString: URLStringConvertible ## URLStringConvertible #>, शीर्षलेख: < #T ## [स्ट्रिंग: स्ट्रिंग]?#>, MultipartFormData: < # टी ## MultipartFormData -> शून्य #>

+0

धन्यवाद एलेसेंड्रो! मुझे एहसास नहीं हुआ था। 'अपलोड' में हस्ताक्षर थे जिसमें 'हेडर' पैरामीटर शामिल थे, आपका समाधान बहुत काम करता है! 'MultipartFormData' का उपयोग करके समाप्त हो गया, भविष्य के संदर्भ के लिए भी मेरा अंतिम कोड पोस्ट करेगा। – mathielo

0

@alessandro-ornano के जवाब मैं multipartFormData का उपयोग कर एक अपलोड हस्ताक्षरित अनुरोध करने में सक्षम था का उपयोग करना:

func uploadProfilePicture(photo: UIImage, callback: apiCallback){ 
    guard let userId = _loggedInUser?["pk"].int else { 
     callback(Response(success: false, responseMessage: "User not logged in")) 
     return 
    } 

    let requestData: requestDataType = ["timestamp": "\(Int(NSDate().timeIntervalSince1970))"] 
    let headers = self.signRequest(requestData) 

    _alamofireManager 
     .upload(.POST, "\(_apiBaseUrl)profiles/\(userId)/photo/", headers: headers, multipartFormData: { formData in 
      if let imageData = UIImageJPEGRepresentation(photo, 1){ 
       formData.appendBodyPart(data: imageData, name: "upload", fileName: "userphoto.jpg", mimeType: "image/jpg") 
      } 
      for (k, v) in requestData { 
       formData.appendBodyPart(data: v.dataUsingEncoding(NSUTF8StringEncoding)!, name: k) 
      } 
     }, encodingCompletion: { encodingResult in 
      switch encodingResult { 
      case .Success(let upload, _, _): 
       upload.responseJSON { response in 
        self.responseHandler(response, callback: callback) // Class' private method 
       } 
      case .Failure(let encodingError): 
       print(encodingError) 
       self.dispatch_callback(callback, response: Response(success: false, responseMessage: "Unable to encode files for upload")) // Class' private method 
      } 
     }) 
} 
संबंधित मुद्दे