This is the third day of my participation in Gwen Challenge

This article is participating in “Java Theme Month – Java Development in Action”, see the activity link for details

The front and back end separation is the general trend, the cross-domain problem is a platitudes, just use the title to Google or Baidu, you can find a large number of solutions, so why write it again, don’t hurry to look down.

Background:

Same Origin Policy. It is an important security metric for client-side scripts, especially JavaScript, to prevent a document or script from being loaded from multiple “origin” sources.

It considers trusted content loaded from any site to be unsafe. When half-trusted scripts run in the sandbox by browsers, they should only be allowed to access resources from the same site, not potentially malicious resources from other sites. Note: Have the same Origin, that is, have the same protocol, host address and port. If one of the three items of data is different, the resource will be considered to have come from a different Origin and therefore will not be allowed access.

CORS was developed to solve the SOP problem. Of course, CORS is not the only solution, but there are no other solutions here.


CORS introduction:

CORS is a W3C standard, which stands for “Cross-origin Resource Sharing”. It allows browsers to make XMLHttpRequest requests to servers across sources (protocol + domain + port), overcoming the limitation that AJAX can only be used in the same source.

CORS requires both browser and server support. Its communication process, is automatically completed by the browser, does not require user participation. For developers, CORS communication is no different from same-origin AJAX/Fetch communication, with the code exactly the same. As soon as the browser discovers that the request is cross-sourced, it automatically adds some additional headers, and sometimes an additional request, but the user doesn’t feel it. Therefore, the key to CORS communication is the server. As long as the server implements the CORS interface, cross-source communication is possible.

Browsers classify CORS requests into two categories: Simple request and not-so-simple Request.

The browser makes a simple CORS request and simply adds an Origin field to the header information.

When the browser makes a CORS request, it adds an OPTIONS query request, called a “preflight” request, before formal communication. The browser asks the server if the domain name of the current web page is on the server’s license list, and what HTTP verb and header fields can be used. The browser issues a formal XMLHttpRequest request only if it receives a positive response; otherwise, an error is reported.

A simple request is a HEAD, GET, or POST request. The HTTP header does not exceed the following fields: Accept, Accept-language, Content-language, last-event-ID, or Content-Type note: Content-type: Application/X-www-form-urlencoded, multipart/form-data, text/plain

Otherwise, it is a non-simple request.

In fact, the implementation of CORS is very simple, is to add some response headers on the server side, and this is insensitive to the front-end, very convenient.

Detailed response header:

  • Access-Control-Allow-Origin

This field is mandatory. The value is either the exact value of the Origin field at the time of the request, or an *, indicating that requests for any domain name are accepted.

  • Access-Control-Allow-Methods

This field is mandatory. Its value is a concrete string or * separated by commas, indicating all methods supported by the server for cross-domain requests. Notice that all supported methods are returned, not just the one requested by the browser. This is to avoid multiple “pre-check” requests.

  • Access-Control-Expose-Headers

This field is optional. In CORS requests, the getResponseHeader() method of the XMLHttpRequest object takes only six basic fields: Cache-control, Content-language, Content-Type, Expires, Last-Modified, Pragma. If you want to get other fields, you must specify access-Control-expose-headers.

  • Access-Control-Allow-Credentials

This field is optional. Its value is a Boolean value indicating whether cookies are allowed to be sent. By default, cookies do not occur, that is: false. This value can only be set to true for requests that have special requirements on the server, such as the request method PUT or DELETE, or the content-Type field Type application/ JSON. If the server does not want the browser to send cookies, delete this field.

  • Access-Control-Max-Age

This field is optional and specifies the validity period of the precheck request, in seconds. There is no need to issue another precheck request during the validity period.

By the way, if you find that there are two requests issued each time, one OPTIONS and one normal request, then you need to configure access-Control-max-age to avoid issuing precheck requests every time.

Solutions:

There are three solutions:

The first method:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/ * *")
                .allowedOrigins("*")
                .allowedMethods("GET"."HEAD"."POST"."PUT"."DELETE"."OPTIONS")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("*"); }}Copy the code

This approach is globally configured, and most of the workarounds on the web are based on older Spring versions, such as:

How does Spring Boot solve the front-end Access-Control-Allow-Origin cross-domain problem

The WebMvcConfigurerAdapter has been marked Deprecated in spring5.0.

/**
 * An implementation of {@link WebMvcConfigurer} with empty methods allowing
 * subclasses to override only the methods they're interested in.
 *
 * @author Rossen Stoyanchev
 * @since 3.1
 * @deprecatedAs of 5.0 {@linkWebMvcConfigurer} has default methods (made * possible by a Java 8 baseline) and can be implemented directly without the  * need for this adapter */
@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {}
Copy the code

Spring’s authors will always comment on outdated classes or methods like this and tell you which one to use. This is good coding practice, thumbs up!

Spring5 supports as little as jdk1.8, so the comments make it clear that you can implement the WebMvcConfigurer interface directly without using the adapter, because jdk1.8 supports default-method.


The second method:
import org.springframework.context.annotation.Configuration;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin"."*");
        response.setHeader("Access-Control-Allow-Credentials"."true");
        response.setHeader("Access-Control-Allow-Methods"."POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age"."3600");
        response.setHeader("Access-Control-Allow-Headers"."Origin, X-Requested-With, Content-Type, Accept"); chain.doFilter(req, res); }}Copy the code

This approach, based on filters, is simple and clear, is to write these response headers in response, a lot of articles are the first way and the second way call you configure, actually this is not necessary, just one way.

Here is also a joke, we do not understand the spirit.


The third way:
public class GoodsController {

    @CrossOrigin(origins = "http://localhost:4000")
    @GetMapping("goods-url")
    public Response queryGoodsWithGoodsUrl(@RequestParam String goodsUrl) throws Exception {}}Copy the code

That’s right ** @crossorigin ** annotation, click on annotation

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {}
Copy the code

As you can see from the @target meta-annotation, annotations can be placed on methods, classes, etc., similar to RequestMapping, that is, methods under the controller can be controlled as a whole, or individual methods can be controlled.

As you can see, this is the least granular cORS control approach, down to the level of a single request.


The above three methods can solve the problem, the most commonly used should be the first, the second, control in their own domain name scope is enough, generally there is no need to make too fine.

If all three configuration methods are used, which one will take effect, similar to CSS style, proximity principle, get the idea.

So when you’re developing a new project, you don’t have to wait for the front end to come to you. I’ve already solved the cross-domain problem.

This article was created BY Telami and licensed under CC BY 3.0CN. Can be freely reproduced, reference, but need to be signed and indicate the author of an article from www.telami.cn/2019/spring…