Cross-domain Ajax request error
- Dominant language
- Scala
- Stars
- 1.4k
- Forks
- 584
- Avg merge
- 14h 33m
- Merged PRs (30d)
- 24
Description
**Issue by [danicheg](https://github.com/danicheg)**
_Friday Jun 17, 2016 at 10:14 GMT_
_Originally opened as https://github.com/akka/akka/issues/20796_
---
_First of all, sorry for the long read._
I use [akka-http-cors](https://github.com/lomigmegard/akka-http-cors) to enable cross origin requests.
Assume on the server side we create users and keep them in Vector:
``` scala
import scala.concurrent.duration._
import akka.actor._
import akka.http.scaladsl.Http
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.model.{HttpResponse}
import akka.http.scaladsl.server.{Directives, RejectionHandler, Route}
import akka.stream.ActorMaterializer
import akka.util.Timeout
import ch.megard.akka.http.cors.CorsDirectives._
import ch.megard.akka.http.cors.{CorsDirectives, CorsSettings}
import scala.concurrent.{ExecutionContext, Future}
import spray.json.DefaultJsonProtocol
trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
implicit val userFormat = jsonFormat3(User)
}
case class User(id: String, name: String, password: String)
class UserService(implicit val executionContext: ExecutionContext) {
var users = Vector.empty[User]
def createUser(user: User): Future[Option[String]] = Future {
users.find(_.id == user.id) match {
case Some(u) => None
case None =>
users = users :+ user
Some(user.id)
}
}
}
trait UserResources extends Directives with JsonSupport {
implicit def executionContext: ExecutionContext
lazy val userService: UserService = new UserService
val settings = CorsSettings.defaultSettings.copy(allowCredentials = false)
val routes: Route = handleRejections(CorsDirectives.corsRejectionHandler) {
cors(settings) {
handleRejections(RejectionHandler.default) {
(path("cors-issue") & post & entity(as[User])) { user =>
userService.createUser(user)
complete(HttpResponse(201))
}
}
}
}
}
object Main extends App with UserResources{
implicit val system = ActorSystem("test-service")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
implicit val timeout = Timeout(10 seconds)
val api = routes
Http().bindAndHandle(handler = api, interface = "0.0.0.0", port = 5000) map { binding =>
println(s"REST interface bound to ${binding.localAddress}")
}
}
```
`build.sbt`:
``` scala
enablePlugins(JavaServerAppPackaging)
name := "cors-issue"
version := "0.1"
scalaVersion := "2.11.8"
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8")
libraryDependencies ++= {
val AkkaVersion = "2.4.7"
val AkkaHttpVersion = "2.4.7"
Seq(
"com.typesafe.akka" %% "akka-slf4j" % AkkaVersion,
"com.typesafe.akka" %% "akka-http-core" % AkkaVersion,
"com.typesafe.akka" %% "akka-http-experimental" % AkkaHttpVersion,
"com.typesafe.akka" %% "akka-http-spray-json-experimental" % AkkaVersion,
"ch.megard" %% "akka-http-cors" % "0.1.2"
)
}
Revolver.settings
```
And if we now test it with cURL:
``` bash
$ curl -v -H "Content-Type: application/json" \
> -X POST "http://localhost:5000/cors-issue" \
> -d '{"id": "123", "name": "123", "password": "123"}'
```
We will get the response:
``` bash
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> POST /cors-issue HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.45.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 47
>
* upload completely sent off: 47 out of 47 bytes
< HTTP/1.1 201 Created
< Server: akka-http/2.4.7
< Date: Fri, 17 Jun 2016 10:08:32 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact
```
That's OK. But if we try to send POST requests using Ajax:
``` javascript
jQuery.ajax({
type: "POST",
url: "http://localhost:5000/cors-issue",
contentType: "application/json",
crossDomain: true,
data: {"id": id, "name": name, "password": password},
dataType: "json",
success: function(status) {
console.log("OK: " + status)
},
error: function(xhr,status,error) {
console.log("NOT OK: " + xhr + " " + status + " " + error)
}
});
```
We will get an error:
`> POST http://localhost:5000/cors-issue 400 (Bad Request)`
Contributor guide
Research direction
Start with the UserResources routes in the posted example and the build.sbt dependencies, then reproduce the request with the curl command and the jQuery.ajax call. Inspect the CORS handling and the differing request payloads; done means the Ajax POST to /cors-issue is accepted and returns the expected 201 response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, jquery, scala
- Domain
- api, backend, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100