Solicitud POST con una cadena simple en el cuerpo con Alamofire

84

¿Cómo es posible enviar una solicitud POST con una cadena simple en el cuerpo HTTP con Alamofire en mi aplicación iOS?

Por defecto, Alamofire necesita parámetros para una solicitud:

Alamofire.request(.POST, "http://mywebsite.com/post-request", parameters: ["foo": "bar"])

Estos parámetros contienen pares clave-valor. Pero no quiero enviar una solicitud con una cadena de valor clave en el cuerpo HTTP.

Me refiero a algo como esto:

Alamofire.request(.POST, "http://mywebsite.com/post-request", body: "myBodyString")
Karl
fuente

Respuestas:

88

Su ejemplo Alamofire.request(.POST, "http://mywebsite.com/post-request", parameters: ["foo": "bar"])ya contiene la cadena "foo = bar" como su cuerpo. Pero si realmente quieres una cadena con formato personalizado. Puedes hacerlo:

Alamofire.request(.POST, "http://mywebsite.com/post-request", parameters: [:], encoding: .Custom({
            (convertible, params) in
            var mutableRequest = convertible.URLRequest.copy() as NSMutableURLRequest
            mutableRequest.HTTPBody = "myBodyString".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
            return (mutableRequest, nil)
        }))

Nota: parametersno debe sernil

ACTUALIZACIÓN (Alamofire 4.0, Swift 3.0):

En Alamofire 4.0 API ha cambiado. Entonces, para la codificación personalizada, necesitamos valor / objeto que se ajuste al ParameterEncodingprotocolo.

extension String: ParameterEncoding {

    public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
        var request = try urlRequest.asURLRequest()
        request.httpBody = data(using: .utf8, allowLossyConversion: false)
        return request
    }

}

Alamofire.request("http://mywebsite.com/post-request", method: .post, parameters: [:], encoding: "myBody", headers: [:])
Silmaril
fuente
Esto funciona perfectamente, no solo para cadenas simples sino para todo tipo de cadenas mapeadas de tipo JSON.
Sahil Kapoor
salvó mi día :) Gracias (y)
ishhhh
1
@silmaril en mi situación, puedo obtener una solicitud sin procesar del backend solo si uso el método PUT, ¿podría ayudarme, por qué la solicitud POST no puede ver nada?
AJ
1
.Custom ya no está disponible en Alamofire 4 Swift 3, y no puedo encontrar la alternativa, ¿alguna pista?
Raheel Sadiq
@Silmaril También publiqué una pregunta, por favor responda eso para poder cerrarla: stackoverflow.com/questions/39573514/…
Raheel Sadiq
64

Puedes hacerlo:

  1. Creé un objeto de solicitud Alamofire separado.
  2. Convertir cadena en datos
  3. Ponga en httpBody los datos

    var request = URLRequest(url: URL(string: url)!)
    request.httpMethod = HTTPMethod.post.rawValue
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    let pjson = attendences.toJSONString(prettyPrint: false)
    let data = (pjson?.data(using: .utf8))! as Data
    
    request.httpBody = data
    
    Alamofire.request(request).responseJSON { (response) in
    
    
        print(response)
    
    }
    
afrodev
fuente
5
Esta debería ser la respuesta aceptada. Es simple, hace exactamente lo que se necesita y sin extensiones ni conversiones innecesarias. Gracias hombre.
Sea Coast of Tibet
2
PD: he "tomado prestada" su respuesta para otra pregunta - stackoverflow.com/a/42411188/362305
Sea Coast of Tibet
2
¿Qué son las asistencias? ¿Puede publicar un fragmento más completo?
SyraKozZ
@SyraKozZ No importa cuáles sean las asistencias, lo único importante es que pjson es una cadena json. Puede poner cualquier cadena json allí.
afrodev
13

Si usa Alamofire, es suficiente codificar el tipo a "URLEncoding.httpBody"

Con eso, puede enviar sus datos como una cadena en el httpbody aunque lo definió json en su código.

Funcionó para mí ...

ACTUALIZADO para

  var url = "http://..."
    let _headers : HTTPHeaders = ["Content-Type":"application/x-www-form-urlencoded"]
    let params : Parameters = ["grant_type":"password","username":"mail","password":"pass"]

    let url =  NSURL(string:"url" as String)

    request(url, method: .post, parameters: params, encoding: URLEncoding.httpBody , headers: _headers).responseJSON(completionHandler: {
        response in response

        let jsonResponse = response.result.value as! NSDictionary

        if jsonResponse["access_token"] != nil
        {
            access_token = String(describing: jsonResponse["accesstoken"]!)

        }

    })
Cemal BAYRI
fuente
1
Actualizaré mi respuesta y escribiré el código usado, porque no pude encontrar cómo escribir código como comentario desde aquí ... Lo siento por tarde. @ Badr Filali
Cemal BAYRI
Gracias tan bien
Badr Filali
1
Me funcionó, pero mi cuerpo necesita ser un JSON, así que cambié la codificación: URLEncoding.httpBody a codificación: JSONEncoding.default y todo funcionó bien.
Ângelo Polotto
Sí @AngeloPolotto gracias por la contribución :) Se trata de codificar el tipo de servicio. Se puede usar dependiendo de su api de descanso como URLEncoding o JSONEncoding.
Cemal BAYRI
Gracias por la respuesta. Pero el problema al que me enfrento es cuando envío una variable en lugar de double quotes stringsy obtengo un código de error 400. ¿Cómo solucionaría eso?
víbora
8

Modifiqué la respuesta de @ Silmaril para extender el Gerente de Alamofire. Esta solución usa EVReflection para serializar un objeto directamente:

//Extend Alamofire so it can do POSTs with a JSON body from passed object
extension Alamofire.Manager {
    public class func request(
        method: Alamofire.Method,
        _ URLString: URLStringConvertible,
          bodyObject: EVObject)
        -> Request
    {
        return Manager.sharedInstance.request(
            method,
            URLString,
            parameters: [:],
            encoding: .Custom({ (convertible, params) in
                let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest
                mutableRequest.HTTPBody = bodyObject.toJsonString().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
                return (mutableRequest, nil)
            })
        )
    }
}

Entonces puedes usarlo así:

Alamofire.Manager.request(.POST, endpointUrlString, bodyObject: myObjectToPost)
raf
fuente
5

Si desea publicar una cadena como cuerpo sin procesar en la solicitud

return Alamofire.request(.POST, "http://mywebsite.com/post-request" , parameters: [:], encoding: .Custom({
            (convertible, params) in
            let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest

            let data = ("myBodyString" as NSString).dataUsingEncoding(NSUTF8StringEncoding)
            mutableRequest.HTTPBody = data
            return (mutableRequest, nil)
        }))
JR
fuente
Hola JITHINRAJ Publiqué una pregunta aquí stackoverflow.com/questions/40385992/… Quiero enviar un cuerpo xml
mike vorisis
5

Lo he hecho para una matriz de cadenas. Esta solución se ajusta a la cuerda en el cuerpo.

La forma "nativa" de Alamofire 4:

struct JSONStringArrayEncoding: ParameterEncoding {
    private let myString: String

    init(string: String) {
        self.myString = string
    }

    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
        var urlRequest = urlRequest.urlRequest

        let data = myString.data(using: .utf8)!

        if urlRequest?.value(forHTTPHeaderField: "Content-Type") == nil {
            urlRequest?.setValue("application/json", forHTTPHeaderField: "Content-Type")
        }

        urlRequest?.httpBody = data

        return urlRequest!
    }
}

Y luego haga su solicitud con:

Alamofire.request("your url string", method: .post, parameters: [:], encoding: JSONStringArrayEncoding.init(string: "My string for body"), headers: [:])
Illya Krit
fuente
4

He usado la respuesta de @afrodev como referencia. En mi caso, tomo el parámetro de mi función como una cadena que debe publicarse en la solicitud. Entonces, aquí está el código:

func defineOriginalLanguage(ofText: String) {
    let text =  ofText
    let stringURL = basicURL + "identify?version=2018-05-01"
    let url = URL(string: stringURL)

    var request = URLRequest(url: url!)
    request.httpMethod = HTTPMethod.post.rawValue
    request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
    request.httpBody = text.data(using: .utf8)

    Alamofire.request(request)
        .responseJSON { response in
            print(response)
    }
}
GeoSD
fuente
¿Qué es exactamente lo que no obtienes?
GeoSD
3

Basado en la respuesta de Illya Krit

Detalles

  • Versión de Xcode 10.2.1 (10E1001)
  • Rápido 5
  • Alamofire 4.8.2

Solución

import Alamofire

struct BodyStringEncoding: ParameterEncoding {

    private let body: String

    init(body: String) { self.body = body }

    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
        guard var urlRequest = urlRequest.urlRequest else { throw Errors.emptyURLRequest }
        guard let data = body.data(using: .utf8) else { throw Errors.encodingProblem }
        urlRequest.httpBody = data
        return urlRequest
    }
}

extension BodyStringEncoding {
    enum Errors: Error {
        case emptyURLRequest
        case encodingProblem
    }
}

extension BodyStringEncoding.Errors: LocalizedError {
    var errorDescription: String? {
        switch self {
            case .emptyURLRequest: return "Empty url request"
            case .encodingProblem: return "Encoding problem"
        }
    }
}

Uso

Alamofire.request(url, method: .post, parameters: nil, encoding: BodyStringEncoding(body: text), headers: headers).responseJSON { response in
     print(response)
}
Vasily Bodnarchuk
fuente
Спасибо вам большое!
Исмаил Хасбулатов
2
func paramsFromJSON(json: String) -> [String : AnyObject]?
{
    let objectData: NSData = (json.dataUsingEncoding(NSUTF8StringEncoding))!
    var jsonDict: [ String : AnyObject]!
    do {
        jsonDict = try NSJSONSerialization.JSONObjectWithData(objectData, options: .MutableContainers) as! [ String : AnyObject]
        return jsonDict
    } catch {
        print("JSON serialization failed:  \(error)")
        return nil
    }
}

let json = Mapper().toJSONString(loginJSON, prettyPrint: false)

Alamofire.request(.POST, url + "/login", parameters: paramsFromJSON(json!), encoding: .JSON)
AndrewK
fuente
¿Qué es Mapper?
Ahmadreza
2

Mi caso, publicando alamofire con content-type: "Content-Type": "application / x-www-form-urlencoded", tuve que cambiar la codificación de la solicitud de publicación de alampfire

de: JSONENCODING.DEFAULT a: URLEncoding.httpBody

aquí:

let url = ServicesURls.register_token()
    let body = [
        "UserName": "Minus28",
        "grant_type": "password",
        "Password": "1a29fcd1-2adb-4eaa-9abf-b86607f87085",
         "DeviceNumber": "e9c156d2ab5421e5",
          "AppNotificationKey": "test-test-test",
        "RegistrationEmail": email,
        "RegistrationPassword": password,
        "RegistrationType": 2
        ] as [String : Any]


    Alamofire.request(url, method: .post, parameters: body, encoding: URLEncoding.httpBody , headers: setUpHeaders()).log().responseJSON { (response) in
IsPha
fuente
0
let parameters = ["foo": "bar"]
              
    // All three of these calls are equivalent
    AF.request("https://httpbin.org/post", method: .post, parameters: parameters)
    AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
    AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .httpBody))
    
    
AbdelraZek
fuente
-3

Xcode 8.X, Swift 3.X

Fácil uso;

 let params:NSMutableDictionary? = ["foo": "bar"];
            let ulr =  NSURL(string:"http://mywebsite.com/post-request" as String)
            let request = NSMutableURLRequest(url: ulr! as URL)
            request.httpMethod = "POST"
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            let data = try! JSONSerialization.data(withJSONObject: params!, options: JSONSerialization.WritingOptions.prettyPrinted)

            let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
            if let json = json {
                print(json)
            }
            request.httpBody = json!.data(using: String.Encoding.utf8.rawValue);


            Alamofire.request(request as! URLRequestConvertible)
                .responseJSON { response in
                    // do whatever you want here
                   print(response.request)  
                   print(response.response) 
                   print(response.data) 
                   print(response.result)

            }
Desarrollador rápido
fuente