ajax sends cross-domain requests to the backend springboot's controller to carry COOKIE across domains to handle ajax cross-domain error problems.

Posted by cmzone on Fri, 26 Jul 2019 05:27:42 +0200

  1. Cause
    Two days of research on springboot, because I just came into contact with springboot, I encountered a lot of problems. First of all, this springboot I built here is no web.xml configuration file, so when I set up the filter, I don't know where to set it up, resulting in a bunch of filter solutions set up by filter in web.xml online.I don't have any use here for solving cross-domain problems. I also have to write a configuration file or a class file. The configuration file does not exist and the class file is not useful.So I looked for a night and finally found the solution and the reason, as detailed below.
  2. The code block for the foreground is as follows
<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8">
  <title></title>
  <!--I'm using 3 here.4.0 Of js-->
  <script type="text/javascript" src="js/jquery-3.4.0.js" ></script>
  <script type="text/javascript" src="js/jquery-3.4.0.min.js" ></script>
 </head>
 <body>
  <!--A simple form Form, Test Passed button Click Events, ajax To post Way of sending requests with carry parameters, so there's no need to write here submit and method-->
  <form method="post">
   //Account: <input type="text" name="userCode" id="userCode"/><br/>
   //Password: <input type="password" name="userPassword" id="userPassword"/><br/>
   <input type="button" value="Sign in" id="button"/>
  </form>
 </body>
</html>
<script type="text/javascript">
 $button = $("#button")
 /*Give a click event when you click a button*/
 $button.click(function(){
  /*Get the value in the input box*/
  var userCode = $("#userCode").val();
  var userPassword = $("#userPassword").val();
  $.ajax({
   type:"post",
   /*Where do you want to send your request*/
   url:"http://localhost:8080/doLogin",
   data:{
    "userCode":userCode,
    "userPassword":userPassword
   },
   /*Set xhrFields: {withCredentials: true}, when true.
   When sending Ajax, Cookie information is brought with Request header, otherwise no Cookie is carried
   Background session.getid() is not the same if the test results are not written or true*/
   xhrFields: {withCredentials: true},
   /*crossDomain: true. When sending Ajax, the Request header contains additional information across domains.
   It will not contain cookie s.*/
      crossDomain: true,
   dataType:"text",
   success:function(result){
   /*If successful, pop the value returned in the background and jump to the page where the login was successful*/
    alert(result)
    window.location.href="index.html";
   },
   error:function(){
    alert("Error")
   }
  });
 })
</script>
  1. The background code block is as follows: Note: This is a springboot project
package cn.test.controller;
import cn.test.pojo.SmbmsRole;
import cn.test.pojo.SmbmsUser;
import cn.test.service.UserService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.List;

/**
 * @RestController Declare this as a controller and return a data type of json
 * @CrossOrigin springboot Support for cross-domain annotations in
 * */
@RestController
@CrossOrigin
public class UserController {
/**
     * @Resource Annotation for automatic injection
     * */
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private UserService userService;
     /**
     * Method of Logon Authentication
     * Accept parameters passed in by ajax
     * You also need session,response,request for some cross-domain settings
     * Kind test, run successfully and return true
     * */
    @RequestMapping("/doLogin")
    public String doLogin(@RequestParam("userCode")String userCode,
                          @RequestParam("userPassword")String userPassword,
                          HttpSession session, HttpServletResponse response,
                          HttpServletRequest request){
        /**
         * Output of the test to send the requested domain name
         * The main code to solve the problem is coming. I have written a lot of notes here in order to make it clear that I have read a lot of data and I hope you can see a little more clearly.
         * */
        System.out.println(request.getHeader("Origin"));
        /**
         *Set'*'in the response header to allow cross-domain request access from all domains
         * More flexible settings allow this domain name to be accessed, request.getHeader("Origin"), through request.getHeader('Origin') to get the domain name of the source to be accessed
         * This line of code is important and must be written
         * */
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        /**
         * The first field, Access-Control-Allow-Headers, indicates that the server allows the field X-PINGOTHER and Content-Type to be carried in the request.
         * Access-Control-Allow-Headers A comma-separated list with a value of
         * This can be written off, which means that the server allows the field to be carried in the request
         * */
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        /**
         * xhrFields.withCredentials: true parameter for client in request sent by foreground ajax
         * The server side runs the client carry certificate access by setting Access-Control-Allow-Credentials = true in the response header.
         * By setting the Credentials parameter, you can maintain the Cookie across domain Ajax.Notice here that:
         * When server-side Access-Control-Allow-Credentials = true, the value of the parameter Access-Control-Allow-Origin cannot be'*'
         * This is because the Cookie information is carried in the first part of the request
         * If the server-side response does not carry Access-Control-Allow-Credentials: true, the browser will not return the response content to the sender of the request.
         * This line of code must also be added
         * */
        response.setHeader("Access-Control-Allow-Credentials", "true");
        System.out.println(session.getId());
        System.out.println("Entered the method of login validation");
        SmbmsUser smbmsUser = userService.getUser(userCode,userPassword);
        session.setAttribute("smbmsUser",smbmsUser);
        if(smbmsUser!=null){
            return "true";
        }else{
            return "false";
        }
    }

 /**
     * Control Layer Method for Increasing Data
     * session,response, is also used here for a series of settings
     * */
    @RequestMapping(value = "/add",method = RequestMethod.POST)
    public Object addSmbmsRole( SmbmsRole smbmsRole,HttpSession session,HttpServletResponse response,
                                HttpServletRequest request){
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        System.out.println("Enter methods to increase data");
        System.out.println(session.getId());
        System.out.println(((SmbmsUser)session.getAttribute("smbmsUser")).getCreatedBy());
        smbmsRole.setCreatedBy(((SmbmsUser)session.getAttribute("smbmsUser")).getCreatedBy());
        smbmsRole.setCreationDate(new Date());
        int count = userService.addSmbmsRole(smbmsRole);
        if(count>0){
            return "true";
        }else{
            return"false";
        }
    }
}
  1. Testing process and some considerations
    First, when the front-end ajax sends the request
crossDomain: true,

This line of code is negligible and has little impact on the results.
While setting up in the foreground, I also found a code that needs to be added above to handle it, but it doesn't work for me, you can try it

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

Tests that leave out crossDomain: true do not affect the run,
The test missed xhrFields: {withCredentials: true} and got two cookies with inconsistent ID s. There was a problem, so xhrFields: {withCredentials: true}, must-have

Test background write-only

response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

The result of the run enters the body of the method, but does not enter the success method when returned, enters the error method, and the page error message is as follows



Background test write-only

response.setHeader("Access-Control-Allow-Credentials", "true");

The result of the run enters the body of the method, but does not enter the success method when returned, enters the error method, and the page error message is as follows

Background Write Only

response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

Will enter the method body in the background, the page will error and pop up the error pop-up window
Test Background Writing

response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Credentials", "true");

Enter the method body successfully, the result returns successfully, enter the success method and pop up the returned result, jump page successfully



The test only writes two of these lines, and the other two combinations fail except when they succeed in writing only two lines of code

response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");

Detailed reasons are detailed in the comments in the code block. If you don't understand them, you can see the following link address

Final outline of how to resolve cross-domain requests from ajax
Add a line of code to ajax as follows (Some people add this line of code to the background without setting it up, but I can't)

xhrFields: {withCredentials: true},

Add the following two lines of code to Controller's method body

response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");

Problem successfully solved!

By the way, if ajax adds code that carries cookies to the method body that you need to operate on session and ajax requests, you can manipulate data without adding those two lines to the method body in the background, but return ing does not properly enter the method body of success until it reaches error Method.But the value was all successful, and it was the same Cookie. The problem is unknown, and when you add those two lines of code behind the scenes, everything works.
Question: Why did I already have cookies with me when I logged in and when I made other ajax requests, so why did I have no problems with the cookies when I was working with their data, but the values really didn't return to the foreground correctly and could not enter success?
There was a new problem just at the time of the test. Ouch, it's a headache and I'm confused.

References I used to solve problems: https://blog.csdn.net/cckevincyh/article/details/81140443
Advanced Data: https://blog.csdn.net/wzl002/article/details/51441704
Advanced data for detailed configuration explanations: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Functional overview

I strongly recommend researching and viewing two advanced materials. Although I can't wake up instantly after I read them once, the explanation of some cross-domain HTTP(CORS) in this data is quite in place. In fact, the reason why I have been able to solve this problem for half a day is that the technology is too shallow. In summary, the foreground ajax can be solved by one line of code, and the background Controller only needs two lines of code, that's three lines of code, but I worked it out overnight. I was tired, and when I found the solution, I suddenly felt like crying...Hope someone can study together after they see it, and also hope to help you!

Topics: Session SpringBoot Javascript xml