Error in sending data as multi form data in play /scala

时间:2015-10-06 08:57:45

标签: scala rest playframework

This is my code the same code is working in play 2.1.5 but I am unable to create war file in play 2.1.5 so I switched to play 2.4.3 and now in response it is coming that 400 bad request client is sending wrong syntactically even post rest api is not hitting. Can some tell me what I am missing?

import play.api._
import play.api.libs.ws._
import play.api.mvc._
//import javax.inject.Inject
import play.api.Play.current
import scala.concurrent.ExecutionContext.Implicits.global
import play.api.libs.ws.WSAuthScheme
import com.ning.http.client.AsyncHttpClient
import com.ning.http.client.multipart.FilePart
import com.ning.http.client.multipart.StringPart
import java.io.File
import org.apache.commons.codec.binary.Base64.encodeBase64

class Application extends Controller {

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }



def postUpload=Action(parse.multipartFormData){request=>

   val groupingType= request.body.dataParts("Grouping type").mkString
    val email=request.body.dataParts("NotificationRecepients").mkString
    val custId=request.body.dataParts("CustomerId").mkString
    val custIdFinal:Int=custId.toInt


   request.body.file("file").map { file =>

  val file1=file.ref.file.getAbsolutePath;


  val fileName = file.filename 
    val contentType = file.contentType

  //file.ref.moveTo(new File("/home/kanchan/Desktop/"+fileName),true)


     val user = "myUser";
      val password = "myPassword";

 val encodedCredentials =
      new String(encodeBase64("%s:%s".format(user, password).getBytes))

    val asyncHttpClient:AsyncHttpClient =WS.client.underlying
    val postBuilder = asyncHttpClient.preparePost(url)
    val builder = postBuilder
      .addHeader("Authorization", "Basic " + encodedCredentials)
      .addBodyPart(new StringPart("selectedGroupType", "Functional Grouping", "UTF-8"))
      .addBodyPart(new StringPart("mailRecipients", "kancgupt@cisco.com", "UTF-8"))
      .addBodyPart(new StringPart("selectedFile", "Sample_group_upload_file.xlsx", "UTF-8"))
      .addBodyPart(new FilePart("file",new File("/home/kanchan/Downloads/Sample_group_upload_file.xlsx")))

    val response = asyncHttpClient.executeRequest(builder.build()).get();
   Ok(response.getResponseBody)


  }.getOrElse {

     Ok( "Missing file")

  }
}
}

Play version 2.4.3 sbt:0.13.8

getting following error: Apache Tomcat/6.0.39 - Error report

HTTP Status 400 - Bad Request

type Status report

message Bad Request

description The request sent by the client was syntactically incorrect.

Apache Tomcat/6.0.39

1 个答案:

答案 0 :(得分:0)

你描述的东西真的很奇怪。我接受了你的代码,curl,REST服务器echo(http://httpbin.org,正好http://httpbin.org/post url),用2.4.3 play创建了一个新的play-scala应用程序。它就像一个魅力。

代码:

package controllers

import play.api._
import play.api.libs.ws._
import play.api.mvc._
import play.api.Play.current
import scala.concurrent.ExecutionContext.Implicits.global
import play.api.libs.ws.WSAuthScheme
import com.ning.http.client.AsyncHttpClient
import com.ning.http.client.multipart.FilePart
import com.ning.http.client.multipart.StringPart
import java.io.File
import org.apache.commons.codec.binary.Base64.encodeBase64

class Original extends Controller {

  def postUpload = Action(parse.multipartFormData) { request =>

    val groupingType = request.body.dataParts("Groupingtype").mkString
    val email = request.body.dataParts("NotificationRecepients").mkString
    val custId = request.body.dataParts("CustomerId").mkString
    val custIdFinal: Int = custId.toInt

    request.body.file("file").map { file =>

      val file1 = file.ref.file.getAbsolutePath;

      val fileName = file.filename
      val contentType = file.contentType

      val url = "http://httpbin.org/post"

      val user = "myUser";
      val password = "myPassword";

      val encodedCredentials =
        new String(encodeBase64("%s:%s".format(user, password).getBytes))

      val asyncHttpClient: AsyncHttpClient = WS.client.underlying
      val postBuilder = asyncHttpClient.preparePost(url)
      val builder = postBuilder
        .addHeader("Authorization", "Basic " + encodedCredentials)
        .addBodyPart(new StringPart("selectedGroupType", groupingType, "UTF-8"))
        .addBodyPart(new StringPart("mailRecipients", email, "UTF-8"))
        .addBodyPart(new StringPart("selectedFile", fileName, "UTF-8"))
        .addBodyPart(new FilePart("file", new File(file1)))

      val response = asyncHttpClient.executeRequest(builder.build()).get();
      Ok(response.getResponseBody)

    }.getOrElse {

      Ok("Missing file")

    }
  }
}

curl命令(来自项目根文件夹):

curl -i -X POST \
   -H "Content-Type:multipart/form-data" \
   -F "Groupingtype=Groupingtype" \
   -F "NotificationRecepients=NotificationRecepients" \
   -F "CustomerId=123" \
   -F "file=@app/controllers/Application.scala" \
 'http://localhost:9000/post'

卷曲响应:

HTTP/1.1 100 Continue

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Tue, 06 Oct 2015 18:38:11 GMT
Content-Length: 3122

{
  "args": {}, 
  "data": "", 
  "files": {
    "file": "package controllers..."
  }, 
  "form": {
    "mailRecipients": "NotificationRecepients", 
    "selectedFile": "Application.scala", 
    "selectedGroupType": "Groupingtype"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Authorization": "Basic bXlVc2VyOm15UGFzc3dvcmQ=", 
    "Content-Length": "3215", 
    "Content-Type": "multipart/form-data; boundary=2EmAF3UE9xSuA6KQpUS3q-Ohzkp0f_7-8", 
    "Host": "httpbin.org", 
    "User-Agent": "AHC/1.0"
  }, 
  "json": null, 
  "origin": "111.111.111.111", 
  "url": "http://httpbin.org/post"
}

尝试创建新的简单项目并使用我的代码 - 然后将您的代码迁移到这个新项目中 - 也许您会找到一些东西。这可能是2.1.5左右的一些错误的迁移步骤。

我的 build.sbt

name := """scala-send-multipart-clean"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.11.6"

libraryDependencies ++= Seq(
  jdbc,
  cache,
  ws,
  specs2 % Test
)

resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"

// Play provides two styles of routers, one expects its actions to be injected, the
// other, legacy style, accesses its actions statically.
routesGenerator := InjectedRoutesGenerator

我的 project / plugins.sbt

// The Play plugin
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.4.3")

// web plugins

addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.0.6")

addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.3")

addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.7")

addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.1.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-mocha" % "1.1.0")

我的 project / build.properties

#Activator-generated Properties
#Wed Oct 07 00:44:35 EEST 2015
template.uuid=7da33b5a-3aef-4d2e-b318-dae93632b999
sbt.version=0.13.8

java版“1.8.0_40”,更新为“build 1.8.0_60-b27” - 没有区别。

  

我收到了这个[StringPart name = selectedGroupType contentType = UTF-8   charset = US-ASCII tranferEncoding = 8bit contentId = null   dispositionType = null,StringPart name = mailRecipients contentType = UTF-8   charset = US-ASCII tranferEncoding = 8bit contentId = null   dispositionType = null,StringPart name = selectedFile contentType = UTF-8   charset = US-ASCII tranferEncoding = 8bit contentId = null   dispositionType = null,FilePart name = file   contentType = application / octet-stream charset = null   tranferEncoding = binary contentId = null dispositionType = null   文件名= Sample_group_upload_file.xlsx]

这是部分中实现toString的方式。这就是全部,它没有说出“正确”或“不正确”的内容。

我的结果

println(builder.build().getParts())

[StringPart name=selectedGroupType contentType=UTF-8 charset=US-ASCII tranferEncoding=8bit contentId=null dispositionType=null, StringPart name=mailRecipients contentType=UTF-8 charset=US-ASCII tranferEncoding=8bit contentId=null dispositionType=null, StringPart name=selectedFile contentType=UTF-8 charset=US-ASCII tranferEncoding=8bit contentId=null dispositionType=null, FilePart name=file contentType=application/octet-stream charset=null tranferEncoding=binary contentId=null dispositionType=null filename=multipartBody1697314279257602964asTemporaryFile]

如您所见,它与您的非常相似,但如果您输出字符串部分的名称和值,我很确定您会收到两者:

import scala.collection.JavaConversions._

... 

builder.build().getParts().map{ part =>
    if(part.isInstanceOf[StringPart]){
      val stringPart: StringPart = part.asInstanceOf[StringPart]
      println(stringPart.getName() + ":" + stringPart.getValue())
    }
}

结果:

selectedGroupType:Groupingtype
mailRecipients:NotificationRecepients
selectedFile:Application.scala