Was having some trouble as chronicled here - https://stackoverflow.com/questions/22570550/play-2-2-1-simpleresult-4xx-response-body-possible-via-cors-xhr
But I didn't focus on nginx since the 200 OK happy path was working as expected. It was 400 level http errors that weren't working as expected. I wasn't receiving a body or able to get the status code inside browser XHR objects.
4xx http errors worked as expected via XHR (readyState=3 experienced) only when I was passing Access-Control-Allow-Origin from the application server, but I don't want this embedded in the code.
Is the only way to pass content and status headers for 4xx responses is to compile with HeadersMoreNginxModule? Not ideal, but doable.
package controllers
import play.api._
import play.api.mvc._
import play.api.libs.iteratee.Enumerator
object Application extends Controller {
def index = Action {
Ok(views.html.index("Your new application is ready."))
}
def goodResponse = Action { implicit request =>
// Ok("Hello world!")
SimpleResult(
header = ResponseHeader(200, Map(CONTENT_TYPE -> "application/json")),
body = Enumerator("Hello world!".getBytes())
)
}
def badResponse = Action { implicit request =>
// BadRequest(
// """{"error":"bad request"}"""
// )
SimpleResult(
header = ResponseHeader(
400,
Map(
CONTENT_TYPE -> "application/json",
ACCESS_CONTROL_ALLOW_ORIGIN -> "*" // FIXME: move to nginx?
)
),
body = Enumerator("""{"error":"bad request"}""".getBytes())
)
}
}
My nginx.conf uses a proxy_pass to the play server on port 9000:
http {
# ...snipped...
upstream api {
server localhost:9000;
}
server {
#listen 80; ## listen for ipv4; this line is default and implied
#listen [::]:80 default ipv6only=on; ## listen for ipv6
listen 80;
listen 443 default_server ssl;
ssl_certificate /usr/local/etc/nginx/ssl/api.crt;
ssl_certificate_key /usr/local/etc/nginx/ssl/nginx.key;
root /usr/share/nginx/www;
index index.html index.htm;
# Make site accessible from https://api/
server_name api;
location / {
# See http://enable-cors.org/server_nginx.html
# Modified to set 'Access-Control-Allow-Origin' "$http_origin"
include nginx_cors.conf;
proxy_pass http://api;
}
}
}
Check your entire nginx configuration and make sure you didn't set
proxy_intercept_errors on;
somewhere. This setting should beoff
in your scenario.