Cross-domain issues
Cross-domain refers to requesting the resources of another domain name from a web page of one domain name, such as currently requesting the JD server (https://www.jd.com) on the Baidu page (https://baidu.com) Resources
Traditional requests will not cross domains
On the a site
, you can submit it through hyperlink
or form form
or window.location.href
Cross-domain access to b site
resources (static or dynamic)
- The essence of the traditional method is to send a request on the address bar to directly jump to the page, instead of obtaining the resources of another page from the current page.
<!--Sending requests through hyperlinks can cross domains--> <a href="http://localhost:8081/b/index.html">Cross-domain access to the index page of site b</a> <br> <!--Requests sent through forms can be cross-domain--> <form action="http://localhost:8081/b/user/reg" method="post"> Username: <input type="text" name="username"><br> Password: <input type="password" name="password"><br> <input type="submit" value="Register"> </form> <br> <!--Sending requests through window.location.href/document.location.href in js code can cross domains--> <button onclick="window.location.href='http://localhost:8081/b/index.html'">Cross-domain access to the index page of site b</button> <button onclick="document.location.href='http://localhost:8081/b/index.html'">Cross-domain access to the index page of site b</button> <!--Use the src attribute of the script tag to load js files across domains --> <script type="text/javascript" src="http://localhost:8081/b/my.js"></script> <br> <!--The src attribute of img can also load images from other sites across domains--> <img src="http://localhost:8081/b/bd_logo.png" />
b site
’s static resource index.html
page
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Bapplication index page</title> </head> <body> <h1>Bapplication index page</h1> </body> </html>
Dynamic resource UserRegServlet
of b site
@WebServlet("/user/reg") public class UserRegServlet extends HttpServlet {<!-- --> @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<!-- --> // Get username and password String username = request.getParameter("username"); String password = request.getParameter("password"); //Respond to the front end response.getWriter().print(username + ":" + password); } }
Ajax request cross-domain issue
Send an Ajax request on the page of site a
to access the resources of site b
. The request initiated at this time is a cross-domain request
<script type="text/javascript"> // Use ES6 new features: arrow functions window.onload = () => {<!-- --> document.getElementById("btn").onclick = () => {<!-- --> // 1. Create core objects (new features of ES6: variables can be defined using the var let const keyword) let xmlHttpRequest = new XMLHttpRequest(); // 2. Register callback function xmlHttpRequest.onreadystatechange = () => {<!-- --> if (xmlHttpRequest.readyState == 4) {<!-- --> // Status codes are acceptable within this range if (xmlHttpRequest.status >= 200 & amp; & amp; xmlHttpRequest.status < 300) {<!-- --> document.getElementById("mydiv").innerHTML = xmlHttpRequest.responseText } } } // 3. Open the channel xmlHttpRequest.open("GET", "http://localhost:8081/b/hello", true) // 4. Send request xmlHttpRequest.send() } } </script> <button id="btn">Send ajax cross-domain request</button> <div id="mydiv"></div>
@WebServlet("/hello") public class HelloServlet extends HttpServlet {<!-- --> @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<!-- --> // response response.getWriter().print("hello ajax!!!"); } }
Due to the browser’s same-origin policy, the browser will intercept the server’s response data, causing the page to be unable to render the server’s response data
# chrome browser error Access to XMLHttpRequest at 'http://localhost:63110/system/dictionary/all' from origin 'http://localhost:8601' has been blocked by CORS policy: No 'Access-Control-Allow- Origin' header is present on the requested resource #firefox browser error Cross-origin request intercepted: The same origin policy prohibits reading the remote resource located at http://localhost:63110/system/dictionary/all (reason: CORS header missing 'Access-Control-Allow-Origin')
AJAX cross-domain solution
Sometimes we need to use ajax for cross-domain access. For example, a company’s page A (a.bjpowernode.com) needs to obtain the resources of page B (b.bjpowernode.com)
Original policy (CORS policy)
The same origin policy means that a script can only read the properties of windows and documents from the same source, which is beneficial to protecting website information)
- Same origin means that the
protocol, domain name, and port
are all the same. Even if two different domain names point to the same IP address, they are not from the same origin. - If there is no same-origin policy, when you enter your account and password on the online banking site and then visit some irregular websites, these websites can access the online banking site just now to obtain your account and password.
When requesting from one address to another, if the protocol, domain name, and port number
are all consistent, it means the same source. If there is an inconsistency, it is a cross-domain request
. This The browser will add origin
to the request header.
- The same-origin policy is a security mechanism of
browsers
. Based on the same-origin policy, the browser determines whether the request initiated by the user is a cross-domain request to prevent the browser from being attacked by XSS, CSRF, etc. - Cross-domain requests only occur between the browser and the server. There are no cross-domain requests between servers.
- Cross-domain does not mean that the request cannot be sent.
The request can be sent and the server can receive the request and return the result normally
. It is just that the response data is intercepted by the browser because the browser thinks that you initiated it. It is a cross-domain request - Browsers are not allowed to share the same
XMLHttpRequest
object across domains because it is unsafe to share the same XMLHttpRequest object.
URL1 | URL2 | Whether it has the same origin | Description |
---|---|---|---|
http://localhost:8080/a/index.html | http://localhost:8080/a/first | Same origin | The protocol domain name and port are consistent |
http://localhost:8080/a/index.html | http://localhost :8080/b/first | Same source | The protocol domain name and port are the same |
http://www.myweb.com: 8080/a.js | https://www.myweb.com:8080/b.js | Different sources | Different protocols |
http://www.myweb.com:8080/a.js | http://www.myweb.com:8081/b.js | Different sources | Different ports |
http://www.myweb.com/a.js | http: //www.myweb2.com/b.js | Different sources | Different domain names |
http://www.myweb .com/a.js | http://crm.myweb.com/b.js | Different sources | Different subdomain names |
CORS (response header) solution
CORS (Cross-origin resource sharing)
is cross-domain resource sharing, which allows the browser to issue XMLHttpRequest requests to cross-origin servers, thereby overcoming the limitation that AJAX can only be used from the same origin
When the server responds to the browser, it adds the response header Access-Control-Allow-Origin
, which tells the browser which sites are allowed to access resources across domains, so that the browser will allow the corresponding sites.
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080"); // Allow a site response.setHeader("Access-Control-Allow-Origin", "*"); // Allow all sites
jsonp solution
jsonp (json with padding)
means that it is json with padding. Similar to ajax requests, it can complete the partial refresh effect and solve cross-domain problems. But it only supports GET requests, not Support POST request
Make a cross-domain request through the src attribute of the script tag
, and the JS code responded by the server will be parsed within the script tag
- The src attribute of the script tag can cross-domain access
static xxx.js resource file
, and can also cross-domain request adynamic Java program
. The result of the request response will be in the script tag. internal parsing
<script type="text/javascript"> //Custom function function sayHello(data){<!-- --> alert("hello," + data.name) } </script> <!----> <script type="text/javascript" src="http://localhost:8081/b/jsonp?fun=sayHello"> //The JS code responded by the server will be parsed within the script tag sayHello({<!-- -->"name" : "jackson"}) </script>
Step 1: Don’t create the script
tag when the page is opened. When we click the button
, create the script element and set the src attribute
code>Send jsonp request to achieve partial page refresh effect
<!--<script type="text/javascript" src="http://localhost:8081/b/jsonp?fun=sayHello"></script>--> <script type="text/javascript"> // Custom function, parameter data is a json object function sayHello(data){<!-- --> document.getElementById("mydiv").innerHTML = data.username } window.onload = () => {<!-- --> document.getElementById("btn").onclick = () => {<!-- --> // Create script element object const htmlScriptElement = document.createElement("script"); //Set the type attribute of script htmlScriptElement.type = "text/javascript" //Set the src attribute of the script htmlScriptElement.src = "http://localhost:8081/b/jsonp?fun=sayHello" //Add the script object to the body tag (this step is to load the script) document.getElementsByTagName("body")[0].appendChild(htmlScriptElement) } } </script> <button id="btn">jsonp solves cross-domain problems and achieves the effect of ajax partial refresh</button> <div id="mydiv"></div>
Step 2: The backend processes the jsonp request initiated by the frontend and responds to a piece of JS code. The backend response is always a string
, but the browser will automatically treat this string as a piece of code. JS code is parsed and executed within the script tag
@WebServlet("/jsonp") public class JSONPSerlet1 extends HttpServlet {<!-- --> @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<!-- --> //Respond to a js code to the front end PrintWriter out = response.getWriter(); //In response to a JS built-in alert function, the browser can directly call it after parsing it. //out.print("alert(123)"); //Directly respond to a programmer-defined sayHello function, the parameter is a json object //out.print("sayHello({"name" : "jackson"})"); //Dynamicly obtain the function name corresponding to the request parameter in the URL. The method parameter is a json object. String fun = request.getParameter("fun"); out.print(fun + "({"name" : "jackson"})"); } }
jQuery encapsulated jsonp
Use jsonp encapsulated by jQuery directly, the underlying principle remains unchanged
<!--The official jQuery library introduced is from the official website--> <script type="text/javascript" src="/ajax/js/jquery-3.6.0.min.js"></script> <script type="text/javascript"> // You don’t need to write this function, jQuery can help you automatically generate a callback function jQuery3600508253314856699_1655528968612(json){<!-- --> // Will continue to automatically call the success callback function } //custom function function sayHello(data){<!-- --> $("#mydiv").html("Welcome:" + data.username) } $(function(){<!-- --> $("#btn").click(function(){<!-- --> //Send an ajax-like request, which is not essentially an ajax request. $.ajax({<!-- --> type: "GET", // jsonp request only supports get request //The actual request sent is /b/jsonp?callback=jQuery3600508253314856699_1655528968612 &_=1655528968613 (timestamp) // callback is the request parameter name, jQuery3600508253314856699_1655528968612 is the random function name url: "http://localhost:8081/b/jsonp",//Specify the cross-domain url dataType: "jsonp", // The specified data type is in jsonp format jsonp: "fun", //Specify the specific request parameter name (previously fun), the default request parameter name is callback jsonpCallback: "sayHello" // Specify a custom callback function name (previously sayHello). By default, jQuery will automatically generate a random callback function. // The callback function automatically generated by jQuery will automatically call the success callback function. /*success: function(data){ // data is a json object used to receive server-side response data $("#mydiv").html("Welcome:" + data.username) }*/ }) }) }) </script> <button id="btn">jsonp encapsulated by jQuery library</button> <div id="mydiv"></div>
Principle of agency mechanism
There will be no cross-domain problems when the pages of this site access the ProxyServlet
of the current site, and then send GET/POST requests through ProxyServlet
to access cross-domain resources
- The first solution (complicated code): Use
JDK built-in API (java.net.URL)
to send HTTP requests - The second option (recommended): Use a third-party open source component to send http requests, such as apache’s open source and free
httpclient
component
Step one: Access the ProxyServlet
in the current site from the page of a site
<script type="text/javascript"> // There is a new syntax arrow function in ES6 window.onload = () => {<!-- --> document.getElementById("btn").onclick = () => {<!-- --> // 1. Create core object const xmlHttpRequest = new XMLHttpRequest(); // 2. Register callback function xmlHttpRequest.onreadystatechange = () => {<!-- --> if (xmlHttpRequest.readyState == 4) {<!-- --> // You can also use the interval method here, because the status code is 200~299, which is the end of the normal response. if (xmlHttpRequest.status >= 200 & amp; & amp; xmlHttpRequest.status < 300) {<!-- --> document.getElementById("mydiv").innerHTML = xmlHttpRequest.responseText } } } // 3. Open the channel xmlHttpRequest.open("GET", "/a/proxy", true) // 4.Send request xmlHttpRequest.send() } } </script> <button id="btn">Use proxy mechanism to solve ajax cross-domain access</button> <div id="mydiv"></div>
Step 2: Send a GET request through the httpclient
component in ProxyServlet
of site a to access the TargetServlet of site b
- The TargetServlet of
b site
will respond the data to the ProxyServlet ofa site
, and then the ProxyServlet will respond the data to the front end.
@WebServlet("/proxy") public class ProxyServlet extends HttpServlet {<!-- --> @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<!-- --> // target address HttpGet httpGet = new HttpGet("http://localhost:8081/b/target"); // Set type "application/x-www-form-urlencoded" "application/json" httpGet.setHeader("Content-Type", "application/x-www-form-urlencoded"); //System.out.println("Calling URL: " + httpGet.getURI()); // httpClient instantiation CloseableHttpClient httpClient = HttpClients.createDefault(); //Initiate a request to access the TargetServlet of site b HttpResponse resp = httpClient.execute(httpGet); // Get the data that TargetServlet responds to ProxyServlet HttpEntity entity = resp.getEntity(); System.out.println("Return status code:" + response.getStatusLine()); // Display the data responded by TargetServlet to ProxyServlet BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); String line = null; StringBuffer responseSB = new StringBuffer(); while ((line = reader.readLine()) != null) {<!-- --> responseSB.append(line); } //System.out.println("Server response data:" + responseSB); reader.close(); httpClient.close(); // Continue to respond to the data returned by the TargetServlet of site b to the front end. response.getWriter().print(responseSB); } }
Step 3: Site b’s TargetServlet
handles the ajax request initiated by site a’s ProxyServlet
@WebServlet("/target") public class TargetServlet extends HttpServlet {<!-- --> @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<!-- --> //Response to a json string response.getWriter().print("{"username":"jackson"}"); } }
Nginx reverse proxy
The implementation principle of the proxy server solution: The same-origin policy is a standard that browsers need to follow, but if the server makes a request to the server, it does not need to follow the same-origin policy
Nginx’s reverse proxy also uses a proxy mechanism similar to ProxyServlet
to complete Ajax cross-domain
- Step 1: The browser first accesses the front-end address page provided by Nginx
http://192.168.101.10:8601
- Step 2: The request initiated by the front-end page will first access a same-origin address provided by Nginx (similar to ProxyServlet)
http://192.168.101.11:8601/api/Specific request initiated by the front-end
- Step 3: Since there is no cross-domain between servers, cross-domain access to the target address
http://www.baidu.com:8601
can be achieved throughProxyServlet
Other common solutions
Common agency solutions
- Node middleware proxy, postMesssage, websocket, window.name + iframe, location.hash + iframe, document.domain + iframe, etc.
- vue-cli (the 8080 server that comes with Vue scaffolding can also be used as a proxy server, but you need to configure
vue.config.js
to enable this proxy. For details, please refer to the article