What is cross-domain?
Cross-domain, in short, is a document or script under a Web application (http://www.a.com) accessing resources under another Web application (http://www.b.com). Any two application domains are considered to be cross-domain as long as there is any difference in protocol, domain name or port.
Why do cross-domain access restrictions occur?
Because of the browser homology policy, we mainly discuss the XmlHttpRequest homology policy. The XmlHttpRequest homology policy prohibits XHR objects from sending requests to different source server addresses, which is a restriction made by browsers for security reasons.
Using ajax to send a request to an application in another domain, the following error will be reported before the server does cross-domain related processing:
Failed to load http://localhost:8081/api: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3200' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
What is CORS?
CORS, full name Cross-Origin Resource Sharing, namely cross-domain (source) resource sharing. CORS uses HTTP header information returned from the target server to identify cross-domain access from a specific domain. Cross-domain requests such as <img> tags loading images from different domains, script styles that refer to CDN, etc. are allowed. However, for security reasons, browsers display cross-domain HTTP requests initiated from scripts, which will be limited if no server-side CORS header information is returned that allows cross-domain because the XMLHttpRequest and Fetch API follow the Same-Origin policy.
CORS mechanism guarantees the security of cross-domain requests and data transmission between browsers and servers, and makes it possible for XMLHttpRequest and Fetch API to access cross-domain.
Two types of cross-domain requests
Simple requests
Simple request means that the current cross-domain request does not trigger "pre-check in cross-domain" (i.e., the pre-check request mentioned later). Simple request needs to satisfy all the following conditions:
- Request method is one of GET, POST or HEAD
- Request headers in request header information are only allowed to appear in the following list
- Accept
- Accept-Language
- Content-Language
- Content-Type, and the value is one of application/x-www-form-urlencoded, multipart/form-data, text/plain
- Last-Event-ID
- DPR
- Save-Data
- Viewport-Width
- Width
- The XMLHttpRequestUpload object does not register event listeners in the request
- ReadableStream object is not used in the request
Examples of request headers and response headers for simple requests:
Preflight requests
The preview request sends a preview OPTIONS request before the real request, verifying whether the final request can be sent safely. Satisfying any of the following conditions is a pre-inspection request:
- Request method is one of PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH.
- Request header information contains any header information other than Accept, Accept-Language, Content-Language, Last-Event-ID, DPR, Save-Data, Viewport-Width, and Width
- Request header information contains Content-Type, whose value is not any of application/x-www-form-urlencoded, multipart/form-data, text/plain.
- Use event listening in the XMLHttpRequestUpload object
- ReadableStream object is used in the request
An example of preview request is that two requests actually occur, one for options verification and one for actual data acquisition:
Key Response Header Information Used in CORS
-
Access-Control-Allow-Origin
The value of this header item can be configured as a wildcard: *, indicating that cross-domain access from any domain is allowed.
Specific domains can also be specified, such as: http://domain.a.com
Note: Origin in request header information of cross-domain request is the domain of request, and cross-domain access can be completed by matching the response header value.
-
Access-Control-Allow-Methods
This header item specifies the request method allowed in cross-domain requests, and can also be configured as a wildcard *, with multiple values separated by commas, such as:
Access-Control-Allow-Methods: GET, POST, OPTIONS, HEAD, PUT
-
Access-Control-Allow-Headers
This header item specifies the header information allowed in cross-domain requests. Since the Content-Type frequently used in requests is not application/x-www-form-urlencoded, multipart/form-data, text/plain, requests will be turned into preview requests. Typically, Content-Type, other commonly used headers and custom header information need to be specified here for cross-domain access. Normal completion
-
Access-Control-Allow-Credentials
When the current web page request specifies withCredentials as true, the back-end return response header needs to specify Access-Control-Allow-Credentials as true. If only the front-end page specifies withCredentials as true when requesting, the back-end return result will be ignored by the browser, thus the request cannot be completed. Cross-domain requests do not send cookies by default. When the front-end web page requests are made, the withCredentials value is set to true, which means that cookie information is allowed to be sent, and of course, the server's explicit permission is also required.
Access-Control-Allow-Credentials: true
Implementation of CORS Solving Cross-Domain Access Restriction
If we want our back-end applications to allow cross-domain requests for certain domains, in general, we need to verify the requests at the interception request and set appropriate response header information for the allowed cross-domain request response.
Typically, a Servlet is used to intercept requests uniformly in a project. At this time, we need to implement our corresponding permissible request methods, such as doGet, doPost to handle ordinary GET/POST requests, and doOptions to handle preview requests.
public class AppServlet extends HttpServlet{ @Override public void init() throws ServletException{ super.init(); } @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ doPost(request, response); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ String origin = request.getHeader("Origin"); List<String> allowOrigins = CORSUtil.getAllowOrigins(); if(StringUtils.isNotBlank(origin) && allowOrigins.contains(origin)){ // Check that the current domain is a domain that allows cross-domain access response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "*"); response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With"); } // compose your response here } /** * To process OPTIONS preview requests across domains, OPTIONS requests also need to specify the domains that are allowed to access. */ @Override protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doOptions(req, resp); String origin = req.getHeader("Origin"); if(StringUtils.isNotBlank(origin)){ resp.setStatus(HttpStatus.SC_NO_CONTENT); //Preview requests are allowed to cross domains, where all OPTIONS requests can cross domains, and actual validation is performed in post resp.setHeader("Access-Control-Allow-Origin", origin); resp.setHeader("Access-Control-Allow-Credentials", "true"); resp.setHeader("Access-Control-Allow-Methods", "*"); resp.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With"); } } }
Or use the Filter filter Filter to process all types of requests one-stop:
public class CorsFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException{ } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{ String origin = request.getHeader("Origin"); List<String> allowOrigins = CORSUtil.getAllowOrigins(); if("OPTIONS".equalsIgnoreCase(request.getMethod) || (StringUtils.isNotBlank(origin) && allowOrigins.contains(origin)){ // Set the necessary response header information to complete cross-domain access for options requests or for domains where the current domain is permissible for cross-domain access response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "*"); response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With"); } } @Override public void destroy(){ } }
web.xml configuration:
<filter> <filter-name>corsFilter</filter-name> <filter-class>com.test.filter.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>corsFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Reference link: