0

I have the Javascript function below. Whenever I run it (calling it from an Android app using WebView), it is sent as an application/x-www-form-urlencoded despite having the dataType: "json" attribute.

If I add contentType: "application/json; charset=utf-8" then the request is not even received from the server and I get error:

XMLHttpRequest cannot load https://example.com/api. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

The request headers look like this:

OPTIONS /api HTTP/1.1
Host: example.com
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8,es;q=0.6

The server is a Java Servlet running on Jetty Embedded that does not even have a WEB-INF or web.xml as it is not a web app but an API. The server does not even receive the request, so I guess it won't be solved by adding response.addHeader("Access-Control-Allow-Origin", "*");

Response header:

HTTP/1.1 200 OK
Allow: POST, TRACE, OPTIONS
Content-Length: 0
Server: Jetty(9.0.z-SNAPSHOT)

Client Javascript

function create(userId, callback) {

  var submitData = {
    "action": "create",
    "userId": userId
  };

  $.ajax({
    data: JSON.stringify(submitData),
    type: "POST",
    url: "https://www.example.com/api",
    dataType: "json"
  })
  .done(function(data) { callback(SUCCESS); })
  .fail(function() { callback(UNKNOWN_ERROR); });
}

EDIT: Tried doing this request without JQuery and still doesn't work.

  var xmlhttp = new XMLHttpRequest();   // new HttpRequest instance 
  xmlhttp.open("POST", "https://www.example.com/api");
  xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
  xmlhttp.setRequestHeader("Access-Control-Allow-Origin", "*");
  xmlhttp.send(JSON.stringify(submitData));
  • 1
    On what container is the servlet running? In tomcat you can easily configure a CORSFilter to allow cross-origin requests. – Harald Gliebe Mar 09 '17 at 11:53
  • @Harald on Jetty –  Mar 09 '17 at 11:54
  • Maybe this document helps: http://www.eclipse.org/jetty/documentation/current/cross-origin-filter.html – Harald Gliebe Mar 09 '17 at 11:56
  • Try to add contentType : "application/json" to your ajax code. – dsp_user Mar 09 '17 at 12:18
  • @Harald it is jetty-embedded and I don't even have a web.xml in the entire application. It is loading all the dependencies from maven. Where can I add those conditions if I don't have a web.xml? It is not a web app. –  Mar 09 '17 at 12:41
  • @dsp_user as explained in the question, it triggers an error –  Mar 09 '17 at 12:45
  • Perhaps you can try with plain javascript (and set the header content type there e.g. xhttp.setRequestHeader("Content-type", "application/json"). If it still doesn't work, you'll know it's not jQuery. – dsp_user Mar 09 '17 at 13:00
  • @dsp_user same error with plain javascript. I edited my question with a response header that is received. –  Mar 09 '17 at 13:52
  • 1
    If I'll have time, I'll try your code when I get home tonight. – dsp_user Mar 09 '17 at 14:06
  • Also, some posts suggest using jsonp (json with padding) instead of json for CORS requests so you may try that as well(http://stackoverflow.com/questions/2887209/what-are-the-differences-between-json-and-jsonp). – dsp_user Mar 09 '17 at 14:37
  • very interesting @dsp_user but jsonp seems to work only with GET requests and in my case it really has to be a POST –  Mar 09 '17 at 14:50
  • 1
    I see now that I had the same issue as you (but for a GET request) and I solved it by adding xmlhttp.setRequestHeader("Access-Control-Allow-Origin", "*"); – dsp_user Mar 09 '17 at 16:19
  • @dsp_user I just tried that with POST and it doesn't work. I believe that header should be on the server side, right? –  Mar 09 '17 at 17:06
  • The header should be set on the client, that's what I did. – dsp_user Mar 09 '17 at 17:15
  • Still the same error, Arturo? – dsp_user Mar 09 '17 at 18:47
  • @dsp_user unfortunately still doesn't work (I copied your code and tried to run it against my jetty server). I believe I need to add some Access-Control code to my jetty config. –  Mar 10 '17 at 10:52
  • 1
    I hope you'll get it working soon. I've had issues with AJAX in the past that I wasn't able to resolve, so yes it can be tricky to make AJAX always work. – dsp_user Mar 10 '17 at 11:00

1 Answers1

0

This works for me (I'm using Tomcat, not Jetty though). I didn't do anything with the JSON payload, just tested if the URL on the server is hit.

AJAX (plain javascript)

function issueAjaxPost(){
  var url = "http://localhost:8085/some_url/servlet/PostJson";
  var json = '{ "action": "create", "userId": userId }';

  xmlhttp.open("POST", url, true);
  xmlhttp.setRequestHeader("Content-type", "application/json");
  xmlhttp.setRequestHeader("Access-Control-Allow-Origin", "*");
  xmlhttp.send(json);
}

Servlet

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException  {
  String url = request.getRequestURL().toString();
  String page = url.substring(url.lastIndexOf("/"));

  ...

  if("/PostJson".equals(page)){
    response.setContentLength("success".length());
    response.setContentType("text/plain");
    response.setStatus(HttpServletResponse.SC_OK);
    response.getWriter().write("success");
  }
}

AJAX callback (the result)

xmlhttp.onreadystatechange = function() {
  if (this.readyState == 4 && this.status == 200) {
    document.getElementById("txt2").innerHTML = this.responseText;      //the result (success)
  }
};
mortalis
  • 2,060
  • 24
  • 34
dsp_user
  • 2,061
  • 2
  • 16
  • 23