I’m developing an iOS app with a server Phoenix. I implemented a feature to upload an image (jpeg) to my server to be send after to AWS S3.
-
Everything work as expected when I send only 1 request but when I’m sending several requests, each one upload an image I start to get the error see below (not for all requests just for some - 7 sent / 4 failed / 3 success )?
-
Also I notified when I got this error, iOS need to keep uploading the all file to get at the end the error, even if the error have been print on the console 1min ago. I do not know if it an issue with Alamofire or Plug ?
Console error
[debug] ** (Plug.Parsers.ParseError) malformed request, a MatchError exception was raised with message "no match of right hand side value: {:error, :timeout}" (cowboy) src/cowboy_req.erl:740: :cowboy_req.stream_multipart/2 (cowboy) src/cowboy_req.erl:675: :cowboy_req.part/2 (plug) lib/plug/adapters/cowboy/conn.ex:71: Plug.Adapters.Cowboy.Conn.parse_req_multipart/3 (plug) lib/plug/parsers/multipart.ex:12: Plug.Parsers.MULTIPART.parse/5 (plug) lib/plug/parsers.ex:215: Plug.Parsers.reduce/6 (my_phoenix) lib/my_phoenix/endpoint.ex:1: MyPhoenix.Endpoint.phoenix_pipeline/1 (my_phoenix) lib/plug/debugger.ex:123: MyPhoenix.Endpoint."call (overridable 3)"/2 (my_phoenix) lib/my_phoenix/endpoint.ex:1: MyPhoenix.Endpoint.call/2 (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4 (cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
Mix file
defp deps do [{:phoenix, "~> 1.2.1"}, {:phoenix_pubsub, "~> 1.0"}, {:phoenix_ecto, "~> 3.0"}, {:postgrex, "~> 0.11.2"}, {:phoenix_html, "~> 2.6"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11.0"}, {:cowboy, "~> 1.0"}, {:comeonin, "~> 2.5"}, {:geo, "~> 1.1.1"}, {:httpoison, "~> 0.9.0"}, {:excoveralls, "~> 0.5.5", only: :test}, {:mailgun, "~> 0.1.2"}, {:pigeon, "~> 0.9.0"}, {:chatterbox, "~> 0.3.0-15-g401cef6", github: "joedevivo/chatterbox"}, {:poison, "~> 2.1", override: true}, {:arc_ecto, "~> 0.4.4"}, {:arc, "0.5.3"}, {:ex_aws, "~> 0.5.0"}] end
Endpoint.ex
plug Plug.Parsers, parsers: [:urlencoded, :multipart, :json], pass: ["*/*"], json_decoder: Poison, read_timeout: 120_000
Route API
scope "/api", MyPhoenix do pipe_through :api ...
post "/upload/image", DataController, :upload end
Swift code to send an image (with Alamofire)
let url = "http://localhost:4000/api/upload"
let header = ["Authorization": "Bearer 123QWE"]
let fileType = ".jpg"
let fileName = "\(NSDate().timeIntervalSince1970)".stringByReplacingOccurrencesOfString(".", withString: "")
let dataImage = UIImageJPEGRepresentation(UIImage(named: "test")! 1)!
let size = Double(imageData.length) / 1024.0
let data: String = dataImage.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
Alamofire.upload(Alamofire.Method.POST, url, headers: header, multipartFormData: { (multipartFormData) in
multipartFormData.appendBodyPart(data: fileType.dataUsingEncoding(NSUTF8StringEncoding)!, name: "file_type")
multipartFormData.appendBodyPart(data: fileName.dataUsingEncoding(NSUTF8StringEncoding)!, name: "file_name")
multipartFormData.appendBodyPart(data: "\(size)".dataUsingEncoding(NSUTF8StringEncoding)!, name: "size")
multipartFormData.appendBodyPart(data: data.dataUsingEncoding(NSUTF8StringEncoding)!, name: "data")
}, encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
self.handleRequest(response)
}
case .Failure(_):
self.handleRequest(nil)
}
}
)
Phoenix API to upload image
def upload(conn, %{"file_type" => file_type, "file_name" => file_name, "size" => image_size, "data" => data_param}) do
changeset = Data.changeset(%Data{})
case Repo.insert(changeset) do
{:ok, data} ->
upload_image(conn, %{id: data.id, file_type: file_type, file_name: file_name, size: image_size, data: data_param, type: Data.data_image})
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(MyPhoenix.ChangesetView, "error.json", changeset: changeset)
end
end
defp upload_image(conn, %{id: id, file_type: file_type, file_name: file_name, size: image_size, data: data_param, type: type}) do
path_image = "/tmp/" <> Token.sign_data("#{id}_#{file_name}") <> file_type
case File.write(path_image, :base64.mime_decode(data_param), [:binary]) do
:ok ->
upload_image_s3(conn, %{id: id, path_image: path_image, size: image_size, type: type})
other ->
conn
|> put_status(:unprocessable_entity)
|> render(MyPhoenix.ChangesetView, "error.json", ErrorData.init_error_upload_data)
end
end






















