DEV Community

Jihao Deng
Jihao Deng

Posted on

FRNT001 Cross Domain, Cross Origin Request

本篇主要讲跨域问题

目前我正在使用spring boot跑后端,node.js跑react前端。后端运行的地址是http://localhost:8080,而前端运行的地址是http://localhost:3000

现在前端想给后端发送一个axios请求,带有参数(比如用户名和密码),后端会返回一些数据。

Existing code

Backends

To make things simple, I just wrote a controller, using @ResponseBody and @RequestParam to recieve parameters in requests.

@Controller
public class IndexController {

    @RequestMapping("/")
    @ResponseBody
    public String hello() {
        return "Hello Spring Boot";
    }

    @RequestMapping(value="/testusername", method=RequestMethod.POST)
    @ResponseBody
    public String testdata(@RequestParam("username") String username, @RequestParam("password") String password){
        return TestDataHelper.getTestJsonUserInfo(username);
    }

}
Enter fullscreen mode Exit fullscreen mode

The method TestDataHelper.getTestJsonUserInfo(username); would return a simple json String as follow:

{
    name: "Alice",
    email: "alice@hue.au",
    pasl: 2323
}
Enter fullscreen mode Exit fullscreen mode

Frontends

In the frontend, axios is used to send requests. In this example, qs is required to make sure backends side can recieve the params.

qs is installed along with axios, simply import it by import qs from 'qs'.

function doLogin() {
  var username = document.getElementById('lgusername').value;
  var password = document.getElementById('lgpassword').value;
  const axios = require('axios');
  axios({
    method: 'post',
    url: 'http://localhost:8080/testusername',
    data: qs.stringify({username, password})  // use qs to stringify data
  }).then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
}
Enter fullscreen mode Exit fullscreen mode

Problem

Starting both projects, and clicking the button which will run doLogin() function, the backend cannot recieve the request:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This is because the browser is blocking it and it usually only allows a request in the same origin for security reasons. Even only port numbers are different, they still be treated as different origins.

Solution

Here, a simple solution on the backend side (spring boot) will be discussed, which implements a filter to allow cross domain requests.

Another solution applying Cross-Origin Resource Sharing (CORS) which I believe is better but more difficult can be found here: https://web.dev/cross-origin-resource-sharing/

For the filter solution, we can simply create a filter package and add a filter class with a @Component annotation:

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;

@Component
public class AccessFilter implements Filter {

    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        // Response to preflight request doesn't pass access control check: 
        // No 'Access-Control-Allow-Origin' header is present on the requested resource.

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000"); // the url that cross domain requests are from
        response.setHeader("Access-Control-Allow-Credentials","true");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With,X-App-Id, X-Token");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");

        chain.doFilter(req, res);

    }

    @Override
    public void destroy() {

    }

}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)