javajqueryreactjsweb-servicescors

CORS issue when trying to do JQuery post with json data, but not with plain text or x-www-form-urlencoded


Issue/Summary:

Issue, i get a CORS error response when doing a jQuery post with application json data. But I don't get that error with jQuery posts with plain/text or x-www-urlencoded-form data.

Issue/Details:

I have two apps running on my Ubuntu VM, a React app running on http://localhost:3000 and a Java web service running from a Payara Server from my Netbeans 10 IDE at this url http://cduran-virtualbox:8080/TestMavenWebApplication/firstservicecall. I'm trying to test doing different jQuery Posts with different content types from the React app to the web service.

To avoid getting a CORS error message I added this to the java web server HttpServletRequest object response.addHeader("Access-Control-Allow-Origin", "http://localhost:3000");

However I'm getting this error when doing a jQuery post with Json data:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://cduran-virtualbox:8080/TestMavenWebApplication/firstservicecall. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

But i have two other test methods that do jQuery Posts (one where the content-type is text/plain and the other is application/x-www-form-urlencoded that don't have that issue. i.e. I successfully can send a jQuery Post message to the web service and get a response back.

Here's the code of the jQuery Post with json data where I have the CORS response issue:

  var urlToPost = 'http://cduran-VirtualBox:8080/TestMavenWebApplication/firstservicecall';

  $.ajax({
     type: "POST",
     dataType: "json",
     contentType: 'application/json; charset=utf-8',
     //crossDomain: true,
     url: urlToPost,
     async:true,
     data: JSON.stringify({ Object: 'CD', Quantity: '4' }),
     success: function(response) {
        console.log("json response: " + response);
    },
    failure: function(errMsg) {
        alert(errMsg);
    }
 }); 

Here's the jQuery post with plain text that works (ie no CORS response, i can see the web service code being reached, and i can see the response back to this React app that initiated the jQuery post):

var urlToPost = 'http://cduran-VirtualBox:8080/TestMavenWebApplication/firstservicecall';

   $.ajax({
       type: "POST",
       //dataType: "text",
       contentType: 'text/plain',
       url: urlToPost,
       data: "Hello from CommunicationForm (plain text)",
       success: function(response) {
         console.log("plain text response: " + response);
       }
   });   

Here's my jQuery post with x-www-urlencoded-form that also works:

  var myObject = {
      var1: 'Hello from CommunicationForm'  
   };
   var urlToPost = 'http://cduran-VirtualBox:8080/TestMavenWebApplication/firstservicecall';

   $.ajax({
       type: "POST",
       //dataType: "text",
       contentType: 'application/x-www-form-urlencoded; charset=utf-8',
       url: urlToPost,
       data: myObject,
       success: function(response) {
           console.log("application/x-www-form-urlencoded response: " + response);
       }
   });

As further evidence, here's a screen shot of my React app, you can ignore the input text field as it does nothing. But I have 3 input submit buttons. As can be inferred from the button names, one does the jQuery post above with x-www-urlencoded-form content type, the other does text/plain, and the other json.

enter image description here

After clicking the x-www.. button this log statement ( as shown in the screenshot) is received back from the web service (indicating it works fine).

application/x-www-form-urlencoded response: Hello back from Servlet - content type received x-www-form-urlencoded

After clicking the plaintext button this log statement is shown on the screen shot which again proves that the jQuery Post works fine:

plain text response: Hello back from Servlet - content type received plain text

The last two console log messages are the CORS error response after clicking the Submit_json button.

EDIT/UPDATE 2:

Additional notes - Using the Post Man app I can send the HTTP Post with application/json as the content type to my Java web service app and saw the response.

I created a regular Maven Java app (not web app) and I can also send an HTTP Post with application/json as the content type to my Java web service app, and I can see the response fine in it.

When I submitted the jQuery POST with application/json from my REACT web app I saw on the network page of the developer tools on the web browser that the POST is sent as an OPTION (this happened in both Firefox and Chrome browsers).

A comment in this link https://github.com/angular/angular/issues/22492 mentions to send simple requests, and lists out content types that don't include application/json.

This does make things more confusing.

EDIT/UPDATE 1:

Here's my back end server code. Nothing too especial, it just checks the content-type header field and then parses the object and sends a different response back to the React app.

public class FirstServlet extends HttpServlet {
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {

        String contentType = request.getHeader("content-type");
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:3000");

        if (contentType.equals("text/plain")) {
            InputStream is = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String line = "";
            while((line = br.readLine()) != null) {
                System.out.println("Plain/Text data received: " + line);
            }
            response.getWriter().print("Hello back from Servlet - content type received plain text");
        } else if (contentType.equals("application/x-www-form-urlencoded; charset=utf-8")) {
            String msgReceived = request.getParameter("var1");
            System.out.println("Message Received: " + msgReceived);            
            response.getWriter().print("Hello back from Servlet - content type received x-www-form-urlencoded");
        } else if (contentType.toLowerCase().contains("json")) {
           JSONObject json = new JSONObject(request.getParameterMap());
           System.out.println("json data received: " + json.toString());
                       response.getWriter().print("Hello back from Servlet - content type received application/json");
        } else {
            response.getWriter().print("Hello back from Servlet - content type undefined");
        }
    }    
}

Solution

  • The only values for the Content-Type header in a simple request are the following:

    Try to change the "application/json" to other content type or the browser will do a preflight request.

    Refer to the CORS documentation: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS