This is the 31st day of my participation in Gwen Challenge. For details, see Gwen Challenge.

Cross-domain request is a common problem in front-end development. Usually, in order to improve the development efficiency, the front and back ends are separated and deployed independently during the project development process, which may lead to inconsistent domain names of the front and back ends and cross-domain problems in the communication process. Because the project development process involves, take this opportunity to sort out cross-domain problems, is also a common problem in front-end interview.

Why is there a cross-domain problem?

The problem is that with the rise of AJAX, Web applications are increasingly demanding cross-domain access, and AJAX is constrained by browser security when making cross-domain requests.

To ensure security, browsers introduce the same origin policy. This strategy restricts the access of resources by Javascript executing on the page. For example, Javascript cannot directly access the DOM structure of the page under different sources, and the server response cannot be obtained when sending requests to different sources (the server will normally process the request and return the response content, But the returned content is blocked by the browser).

What is the same origin policy?

SOP (Same Origin Policy) is a convention introduced by Netscape in 1995. SOP is the core and most basic security function of the browser. Without the Same Origin policy, the browser is vulnerable to XSS and CSFR attacks. Same-origin means that the protocol, domain name, and port are the same. Even if two different domain names point to the same IP address, they are not same-origin.

The same origin policy restricts the following behaviors:

  • Cookie,LocalStorageIndexDBUnable to read
  • DOMJavascriptObject not available
  • AJAXRequest receive limit

What is cross-domain

URL instructions Whether to allow communication
http://www.devpoint.cn/name1.jshttp://www.devpoint.cn/name2.js Different paths for the same domain name allow
http://www.devpoint.cn:8080http://www.devpoint.cn Different ports for the same domain name Don’t allow
http://www.devpoint.cnhttp://crayon.devpoint.cn The primary domain is the same, but the subdomain is different Don’t allow
http://www.devpoint.cnhttp://www.aliyun.com Primary domain different Don’t allow
http://www.devpoint.cnhttps://www.devpoint.cn Agreement is different Don’t allow

The solution

jsonp

In order to reduce the load of the Web server, static resources such as JS, CSS and IMG are separated to another server with an independent domain name, and static resources are loaded from different domain names through corresponding tags in the HTML page. This is allowed by the browser. Based on this principle, script can be dynamically created. Request a reference url to achieve cross-domain communication.

Limitations: Only GET requests

HTML code:

<script type="text/javascript"> function onLogin(res){ console.log(res); } < / script > / / reference file < script type = "text/javascript" SRC = "https://www.devpoint.cn/login?user=devpoint&callback=onLogin" > / / AJAX, With jquery. Js < script type = "text/javascript" > $. Ajax ({url: "https://www.devpoint.cn/login", type: "get", dataType: "json", JsonpCallback :"onLogin", // custom callback data:{}}); </script>Copy the code

Server-side code (PHP) :

echo "onLogin({"result":"success", "user": "devpoint"})"
Copy the code

document.domain + iframe

Implementation principle: Two pages are forced to set as the same primary domain through Javascript document.domain to achieve the effect of co-domain, that is, the pages in iframe are communication proxy pages, proxy pages must be deployed in the same site with the back-end server.

Limitations: Only cross domains with the same primary domain name and different subdomains.

Home page: (assuming the access path is: https://blog.devpoint.cn/login.html), the code is as follows:

<iframe id="proxyIframe" src="https://api.devpoint.cn/proxy.html"></iframe>
<script type="text/javascript"> 
    document.domain = "devpoint.cn";
    const user = "devpoint";
    const elemIframe = document.getElementById("proxyIframe");
    elemIframe.login(user,function(res){
        console.log(res);
    });
</script>
Copy the code

Agent page: https://api.devpoint.cn/proxy.html, the code is as follows:

<script type="text/javascript"> document.domain = "devpoint.cn"; } function login(user,callback){ajax(data,callback); } </script>Copy the code

location.hash + iframe

Implementation principle: A wants to communicate with B across domains through the middle page C.

Limitations: Cumbersome, and the length of the value passed by location.hash is limited

Three pages, different fields use iframe location.hash to transfer values, the same fields directly js access to communicate.

A domain: A.html -> B domain: B.html -> A domain: C.HTML, A and B different domains through hash value one-way communication, B and C are also different domains can only one-way communication, but C and A are the same domain, so C can access all objects on A page through parent. Parent.

A.h HTML code (http://www.devpoint.cn/a.html) as follows:

<iframe id="iframe" src="http://www.crayon.dev/b.html" style="display:none;" ></iframe> <script type="text/javascript"> var iframe = document.getElementById("iframe"); SetTimeout (function() {ifame. SRC = ifame. SRC + "#user=devpoint"; }, 1000); Function onCallback(res) {alert("data from c.html --> "+ res); } </script>Copy the code

B.h HTML code (http://www.crayon.dev/b.html) as follows:

<iframe id="iframe" src="http://www.devpoint.cn/c.html" style="display:none;" ></iframe> <script type="text/javascript"> var iframe = document.getElementById("iframe"); Onhashchange = function () {ifame. SRC = ifame. SRC + location.hash; }; </script>Copy the code

C. the TML (http://www.devpoint.cn/c.html) code is as follows:

<script type="text/javascript"> // Listen for hash values window.onhashchange = function () { The results back to the window. The parent. The parent. OnCallback (" hello, "+ location. Hash. Replace (" # user =", "")); }; </script>Copy the code

postMessage

PostMessage is an API in HTML5 XMLHttpRequest Level 2, and is one of the few window properties that can operate across domains. It can be used to solve the following problems:

  • Data transfer between the page and the new window it opens
  • Messaging between multiple Windows
  • Pages with nestediframeMessaging, including offline files (HTML packaged with APP and installed on local pages)
  • Cross-domain data transfer for the three scenarios above

The postMessage(data, Origin) method takes two arguments:

  • dataThe HTML5 specification supports any primitive type or copiable object, but some browsers only support strings, so it’s best to use them when passing argumentsJSON.stringify()Serialization.
  • origin: Protocol + host + port number. The value can also be “*”, which indicates that the port can be sent to any window. If you want to specify the same source as the current window, set this parameter to “*”/

CORS

Common cross-domain request: Access-Control-allow-Origin can be set on the server, and the front-end does not need to be set.

Cross-domain requests require cookies: both the front and back ends need to be set.

Note that due to the restriction of the same-origin policy, the cookie read is the cookie of the domain where the cross-domain request interface resides, not the current page.

Currently, all browsers support this feature, and CORS has become a mainstream cross-domain solution. Cross-domain requests for the DEBUG functionality in a project use this scheme.

Front-end Settings: The withCredentials attribute needs to be set in the request header

headers: {
    "x-fdn-sign": apiSign,
    withCredentials: "true"
}
Copy the code

Server Settings

response.setHeader("Access-Control-Allow-Origin", "*"); Responsetheader (" access-Control-allow-credentials ", "true"); response.setHeader(" access-Control-allow-credentials ", "true");Copy the code

conclusion

Although modern front-end development rarely touches on cross-domain issues, it is mostly through framework or scaffolding agents, or NGINX agents, etc. But it’s worth knowing as a basis.