Spring REST service prevents Cross-Origin Requests with AJAX

Having Trouble Accessing Spring REST Service

My spring service

@RequestMapping(value = "/MAS/authenticate", method = RequestMethod.POST)
public ResponseEntity<Map<String, String>> authenticate(@RequestBody Subject subject) {
    Map<String, String> result = new HashMap<String, String>();
    result.put("result_detail", "Invalid Password");
    result.put("result", "failure");
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.setContentType(MediaType.APPLICATION_JSON);
    responseHeaders.add("Access-Control-Allow-Origin", "*"); // also added header to allow cross domain request for any domain
    return new ResponseEntity<Map<String, String>>(result, responseHeaders, HttpStatus.OK);
}

My AJAX code

$.ajax(
{
  crossDomain: true,
  type: "POST",
  contentType: "application/json; charset=utf-8",
  async: false,
  url: "http://localhost:8080/SpringMVC/rest/MAS/authenticate",
  headers: {"Access-Control-Allow-Origin" : "*"},
  data:{},
  dataType: "json", //also tried "jsonp"
  success: function(data, status, jqXHR)
  {
    alert('success');
  },
  error: function(jqXHR, status)
  {
    alert('error');
  }
});

Encountering the Following Error:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/SpringMVC/rest/MAS/authenticate. This can be fixed by moving the resource to the same domain or enabling CORS.

Attempted using dataType: "jsonp", but it appends my body object into URL resulting in a different URL and hence cannot hit my service URL, resulting in a 404 error.

Browser in use: Firefox version 36.0.4

Seeking assistance on resolving this error, any suggestions?

Answer №1

After extensive research, I discovered that the issue was not with my AJAX call or service, but rather a server-side problem.

To resolve CORS requests on the server side using Spring, it is necessary to implement a filter like the one below:

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;

public class CustomCORSFilter extends OncePerRequestFilter {
    private static final Log LOG = LogFactory.getLog(CustomCORSFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        response.addHeader("Access-Control-Allow-Origin", "*");
        if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
            LOG.trace("Sending Header....");
            // CORS "pre-flight" request
            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
            response.addHeader("Access-Control-Allow-Headers", "Content-Type");
            response.addHeader("Access-Control-Max-Age", "1");
        }
        filterChain.doFilter(request, response);
    }

}

Lastly, don't forget to apply this filter in your web.xml file for your service requests:

    <filter>
        <filter-name>customCorsFilter</filter-name>
        <filter-class>com.example.package.CustomCORSFilter</filter-class> 
    </filter>
    <filter-mapping>
        <filter-name>customCorsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping> 

Hopefully, this solution will assist others facing similar challenges. :)

Answer №2

Typically, only the GET method is permitted by default and POST is not allowed on your server side:

Access-Control-Allow-Origin: *

The above header grants CORS access, but you should include this as well:

Access-Control-Allow-Methods: POST, GET

For a more detailed guide on HTTP access control (CORS), visit the Mozilla project page

Your code snippet should resemble the following:

responseHeaders.add("Access-Control-Allow-Methods", "POST, GET"); // also added header to allow POST, GET method to be available
responseHeaders.add("Access-Control-Allow-Origin", "*"); // also added header to allow cross domain request for any domain

Update:

Upon reviewing the article again, I discovered some key points:

A simple cross-site request is one that:

  • Only uses GET, HEAD or POST. If POST is used to send data to the server, the Content-Type of the data sent to the server with the HTTP POST request is one of application/x-www-form-urlencoded, multipart/form-data, or text/plain.
  • Does not set custom headers with the HTTP Request (such as X-Modified, etc.)

As indicated in bold, you need to adjust the Content-Type of your data (currently set as

contentType: "application/json; charset=utf-8",
) or explore the preflight technique outlined later:

  • It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
  • It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)

Therefore, consider adjusting the contentType or incorporating this header into your request:

Access-Control-Request-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE

along with these headers in your response:

Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE

Once done, try calling your method again.

Answer №3

Here is the solution for making cross-platform calls to a Spring Boot web service.

To access the application, use the following URL: http://example.com:8080

The webservice can be accessed using this URL: http://example.com:9090

To enable cross-origin requests in your Spring controller, add the following annotation:

@CrossOrigin(origins = "http://example.com:8080")
@RequestMapping(value = "/uri", method = RequestMethod.GET)
public SomeObject someMethod(){
// insert your logic here
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieve pixel information upon touch in an Appcelerator Titanium application on Android or iPhone

Can pixel level data of an image view be accessed using Titanium Mobile on Android/iPhone? ...

Comparison between Mobile Phone's innerWidth and innerHeight Versus Resolution

My test phone, the Galaxy S3 Mini, has a resolution of 800x480 according to its specs. Strangely, when I run the following code in my HTML game: window.innerWidth window.innerHeight The width appears as 533 and the height as 295. I recently discovered ...

Can anyone shed some light on why the CSS code is not functioning properly within my HTML file?

My CSS doesn't seem to be working in my HTML. I have linked it correctly, but it's not displaying properly - even showing empty in the CSS tab of Chrome Inspector. The links are there, so I'm not sure why it's not functioning correctly. ...

What are the steps to integrate Webpack into an EJS Reactjs Express MongoDb application?

I have incorporated EJS, Express/NodeJs, and MongoDB into the project, along with ReactJs as an addition. My next step is to introduce Webpack for bundling both EJS and ReactJs files together. Although the end goal is to transition the p ...

The function of jQuery .click() not triggering on elements within msDropDown

I'm having difficulty implementing jQuery on an Adobe Business Catalyst site. The HTML snippet below shows the structure: <div class="banner-main"> <div class="banner-top"> <section class="banner"> <div class="catProd ...

Make sure to update the package.json file at multiple locations following the execution of the "npm i" command

My goal is to automatically detect any newly installed packages based on my package.json file. This way, whenever I run "npm i", the new package will be added not only to the usual "dependencies" section but also to a custom section called "extDependenci ...

"Is there a way to modify the color of the button once it's been clicked, but only for the specific button that was

Looking to create a Quiz App using React and facing an issue where all buttons change color when clicked, instead of just the one that was clicked. Any solutions on how to make only the clicked button change its color in React.js? App.js import Main from ...

What could be causing the lack of downward rotation of my arrow in css? (specifically, the span element)

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=de ...

The absence of essential DOM types in a TypeScript project is causing issues

Recently, I've been working on setting up a web app in TypeScript but I seem to be missing some essential types that are required. Every time I compile using npm run build, it keeps throwing errors like: Error TS2304: Cannot find name 'HTMLEleme ...

Using Node.js and TypeScript to define custom data types has become a common practice among developers

I offer a variety of services, all yielding the same outcome: type result = { success: boolean data?: any } const serviceA = async (): Promise<result> => { ... } const serviceB = async (): Promise<result> => { ... } However, th ...

Managing file uploads using the Selenium Server Standalone involves implementing code to interact with

When attempting to run a testsuite on a remote host using the Selenium Standalone Server for file uploads, I encountered an issue. The code snippet I used to handle file uploads is as follows: FileBrowserDialogHandler fileBrowserDialogHandler = new FileBr ...

Excessive Function Calls Detected in AngularJS Application

I'm facing a major performance issue. I need to display details in a list, but the function is being called excessively. Feel free to check out the demo here Here's the HTML code snippet : <div ng-controller="MyCtrl as ctrl"> <p>K ...

Executing JQuery asynchronous calls sequentially

Recently delving into the world of Jquery, I've encountered a coding challenge: my code loops through an array and retrieves HTML from an ajax request for each iteration. $.each(arr, function (data) { $.get('/Quote/LoadQuoteItemCost', { ...

Leveraging the power of the Twitter API to integrate real-time tweets into custom code

Looking for an API that can transform a tweet from Twitter into a string format suitable for integration into a program or website. Any recommendations? ...

Having a problem with the hover effect on the navbar component

Whenever I hover over the individual links, I notice that the color change doesn't extend all the way up. I have a feeling there is a more efficient way to achieve this than my current approach. Any assistance would be greatly appreciated! HTML: < ...

The height of the ReactPlayer dynamically adjusts to accommodate content beyond the boundaries of the page

I have a video on my webpage that I want to take up the entire screen, but currently, users have to scroll a bit to reach the bottom, which is not ideal. This is my JavaScript: <div id="page"> <div id="video-container"> ...

Error encountered in SelectInput.js file of React MUI 4: line 340 - TypeError: Unable to access properties of undefined (specifically 'value')

An issue arises when an empty array is provided as the options. The error message: SelectInput.js:340 Uncaught TypeError: Cannot read properties of undefined (reading 'value') at SelectInput.js:340:1 at Array.map (<anonymous>) ...

The MaterialUI Datagrid is throwing an error message for an Invalid Hook Call

Having a strange issue with my simple component. I've imported DataGrid from MaterialUI, defined variables for columns and rows, and rendered the DataGrid in a functional component. However, I'm getting an "invalid hook call" error. Most solution ...

Creating JSON arrays with JavaScript and jQuery

User Information var Users=[{"Id":1,"FirstName":"John"},{"Id":2,"FirstName":"Emily"}] Call Information var CallInfo=[{"Id":1,"PercentageCalls":"22 %","TotalTime":"60:24 minutes","PercentageTime":"0 %","AvgTime":"0:22 minutes"},{"Id":2,"PercentageCa ...

Do I need to include a callback in my AWS Lambda handler function?

What is the function of the callback in the lambda handler? It appears to be utilizing the sns variable and I am looking to make some modifications to the variables. exports.handler = function(event, context, callback) { console.log("AWS lambda and ...