preface

Year after year job-hopping season, ready to start from the interview content to see the front-end related knowledge points, aimed at exploring a series of knowledge points, ability within the scope of in-depth exploration. Focus on practice, for the primary front-end and prepare for the interview of the students, try to attach actual code examples and related questions ~ series name is used [bald break front-end interview] — because the circle of consensus, technology is proportional to the amount of hair. 😄 hope we can break the bottleneck as soon as possible ~

There are too many articles about interview questions or certain knowledge points. Here I just want to record my personal summary in the form of code warehouse and output the article. After all, theory is not equal to practice

Related series of articles of the same type:

  • Bald front end interviews – HTTP && HTTPS
  • Bald front end interview – Web security related
  • Bald front End Interview — A summary of cross-field practice

Other types:

  • Bare front end interview – Promise && Async/Await
  • .
  • Bald broken series more addresses

What is cross-domain

Today we are going to talk about cross-domain practice ~ why we need to add practice, because cross-domain is something I believe you have read enough in theory. If it is an interview, it may be enough to say a few solutions, and the interviewer will not ask you to write code, but have you really used it? Do you really understand how this works? Based on this point of view, I wrote the following cross-domain article based on practice.

Specifically, see the above article “Web Security related” should be a general understanding. If not, here is a brief overview.

When the front-end page requests a URL address, the URL must be in the same domain as the URL on the browser, that is, the domain name, port number, and protocol are the same. If any of them are different, it’s cross-domain.

The direct code screenshot is more intuitive:

// List app.get(); // List app.get()'/list', (req, res) => {
  const list = [
    {
      name: 'luffy',
      age: 20,
      email: '[email protected]' 
    }, {
      name: 'naruto',
      age: 24,
      email: '[email protected]'
    }
  ]
  res.status(200).json(list);
});
Copy the code

Browser visit:

Write another HTML page to invoke this interface:

<script>
  window.onload = function() {
    const xhr = new XMLHttpRequest();
    xhr.open('GET'.'http://localhost:3000/list');
    xhr.onreadystatechange = function () { 
      if(xhr.readyState === 4 && xhr.status === 200) { const resData = JSON.parse(xhr.responseText); console.log(resData); }}; xhr.send(); } </script>Copy the code

As you can see, this is cross-domain, I believe that people who have just learned the front end and do not understand the background often see it.

Cross-domain: In short, what we usually mean by cross-domain is that browsers are not allowed to execute scripts from other sites, subject to the browser’s same-origin policy.

Cross-domain solutions

There are a variety of ways to solve cross-domain problems, but frankly speaking, we usually use only two or three, but since it is a summary, we will sort out all kinds of strange skills ~

Personally, in the process of team project development, the front end is not very suitable for cross-domain processing, most of the scene cross-domain should be processed by the back end, so here is just a brief discussion of the development process of this cross-domain solution.

The most popular cross-domain solution — CORS

If cross-domain is involved in current projects, in fact, it should be solved by setting CORS on the backend. CORS is the most mainstream cross-domain solution at present. Cross-domain Resource sharing (CORS) is a mechanism that uses extra HTTP headers to tell browsers to allow Web applications running on one Origin (domain) to access specified resources from different source servers.

// Set the request header(res.header) on node to accept requests from all source addresses.'Access-Control-Allow-Origin'.The '*');
res.header('Access-Control-Allow-Methods'.'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers'.The '*');
Copy the code

Restart the service and refresh the page:

As you can see, the data is retrieved and the cross-domain resolution is complete

Generally speaking, node.js can use the community’s mature CORS scheme directly

The most classic cross-domain solution – JSONP

Next is the JSONP solution, which is the most classic, although most projects do not use it to solve cross-domain, but any interview, when it comes to cross-domain, will basically ask this knowledge.

Principle, non-homologous restriction of labeling

Homology restriction is the essence of cross-domain, that is, there is no such thing as homology restriction, then there is no cross-domain. In fact, there are some tags that have no homology limitation —

Step 1: Assume there is an interface in the background/jsonp/list

<button onclick="loadJsonpData()"</button> <script>function loadJsonpData() {
    const script = document.createElement('script');
    script.src='http://localhost:3000/jsonp/list';
    document.body.appendChild(script);
  }
</script>
Copy the code

Clicking the button inserts a

Step 2: Agree the name of the execution function on the front and back ends

As mentioned in the first step, loading the specified URL into the page with the

Let’s say the convention is that the function is called callbackData

Step 3: The front end defines callbackData

If the function name is specified, the front end must define it, because the back end returns a piece of executable code. If the front end is not defined, the error callbackData undefined is reported.

// Define callback function to get background datafunction callbackData(data) {
    console.log(data, 98989);
}
Copy the code

Step 4: Return the executable code with the data in the background

The front and back end agreed on the name, and the front end defined the function, the parameter is the data you want to get, the background only need to respond back to the packet in the execution function.

Note that the JSONP interface differs from the normal interface in that instead of returning JSON-formatted data, it returns an executable string that is executed by the front end.

app.get('/jsonp/list', (req, res) => {
  const list = [
    {
      name: 'luffy',
      age: 20,
      email: '[email protected]' 
    }, {
      name: 'naruto',
      age: 24,
      email: '[email protected]'}] const resData = 'callbackData' (${JSON.stringify(list)}) `; res.send(resData); // We can't use res.json but res.send});Copy the code

Let’s execute it:

As you can see, when you click the button, the browser Network JS will request the newly inserted

On the front end, because callbackData(data) is defined, the console can see that it prints the background response.

Above is the basic process of JSONP, I do not know to explain to you did not explain clearly, in fact, it is really very simple, but in the past, I feel that all people speak very official, and there is no actual operation, so that many people will misunderstand or do not understand, here I will explain through the actual code, I believe it will be easy to understand ~

In fact, JSONP can also be encapsulated, and it can be implemented beautifully. Jquery, for example, has built-in support for JSONP.

// jquery jsonp
$.ajax({
	url: "http://cross-domain/get_data",
	dataType: "jsonp"// Specify the data type returned by the server jsonp:"callback"// Specify the parameter name jsonpCallback:"callbackName"// specify the callback function}).done(function(resp_data) {
	console.log("Ajax Done!");
});
Copy the code

Here I will not encapsulate, because understand the principle of the line, now the front end should be rarely used, only for interviews.

Also, although I usually use the

The simplest cross-domain solution – NGINX

This is not an introduction. To be honest, it is not a front-and-back cross-domain solution, but an o&M solution, and this is not what the interviewer should expect when asked about cross-domain relevance.

A simplified version of NGINX addresses cross-domain configuration as follows:

server
{
    listen 3003;
    server_name localhost;
    location /ok {
        proxy_pass http://localhost:3000;

        # specify methods that are allowed across domains, * for all
        add_header Access-Control-Allow-Methods *;

        # precheck the cache of the command, if not cached will send two requests each time
        add_header Access-Control-Max-Age 3600;
        # Cookie requests require this field and set to true
        add_header Access-Control-Allow-Credentials true;

        # indicates that this domain is allowed to make cross-domain calls (the domain name and port from which the client sends the request)
        # $http_origin does not use * because requests with cookies do not support *
        add_header Access-Control-Allow-Origin $http_origin;

        # represents the dynamic retrieval of fields in the request header
        add_header Access-Control-Allow-Headers 
        $http_access_control_request_headers;

        The request will not be sent until the precheck command passes
        Check whether the type of request is a precheck command
        if ($request_method = OPTIONS){
            return200; }}}Copy the code

The theoretical cross-domain solution — window.name

It’s a theoretical cross-domain solution that means it does deliver data across domains, but it’s rarely used. MDN says so (as SessionVars and Dojo’s Dojox.io. WindowName), which is also used as a safer alternative to JSONP to provide cross-domain messaging. But these two frameworks I also really do not know, there are applications and compatibility is very good, except for the eternal IE may not support, other browsers support.

Let’s take a quick look at what window.name is:

  • Each browser window (Tab page) has a separate window.name corresponding to it
  • Before a window (Tab page) is opened or closed, the window is loadedallPages share one at a timewindow.name, the window below each page faceswindow.nameBoth have read and write permissions.
  • window.nameIs the property of the current window (Tab page) and does not change when the page jumps.
  • window.nameThe capacity is about 2MB and the storage format is string

It sounds a little pale, but let’s take a look at some practical examples.

Above, set window.name = aaaaa at http://127.0.0.1:3006, then the page jumps to http://127.0.0.1:3008. According to the same origin policy of the browser, this is a cross-domain scenario. The window.name of the previous page is correctly retrieved. As mentioned above, each window is shared, but what about different ports?

// code to open a new window'_blank' href='http://127.0.0.1:3008/'> Jump to port 3008 </a>Copy the code

As you can see, window.name is indeed independent between Windows (Tab pages), new Windows are opened, and window.name is initialized with an empty string.

Array A; Object B; window.name; toString(); window.name;

Of course, if the interviewer really asks this question, this answer is actually not a big problem, but there is still a flaw, because there is a special case, is ES6 new basic type Symbol.

The actual usewindow.nameCross-domain data acquisition

For example, in the first Demo, I set window.name in A and then jump to B to get the value set by A. Is this called cross-domain? Wouldn’t it be easier for me to add the value to the parameter when I jump, so it’s not the actual scenario. Here’s a real scenario:

[Problem Description] : There are two different domain pages A and B. Window. name is used to obtain window.name set on PAGE B when loading A.

For A moment, all page B does is to set the data in window.name, so when we load page A, we go to page B to get the data, and then we can’t jump to page B and then go back to page A, because obtaining data is an asynchronous scenario without refreshing the page. If you want to create an iframe on the A page — let’s say proxy.html, we call it A transit page, and then we open the B page in the transit page, Get B’s window.name data set in advance. The whole process is roughly as follows:

Here is the code:

http://127.0.0.1:3006/a-data.html -> A page http://127.0.0.1:3006/a-data.html -> Proxy data transfer page -> just an empty page http://127.0.0.1:3008/b-data.html - > page ___________________________________________ B / / B - data. The HTML < script > const data  = [ { name:'luffy',
      age: 20
    }, {
      name: 'naruto',
      age: 22
    }
  ]
  window.onload = function() {
    window.name = JSON.stringify(data);
  }
</script>

// a-data.html
<script>
  const currentDomain = 'http://127.0.0.1:3006'; // Current field const corssDomain ='http://127.0.0.1:3008'; // cross-domain window.onload =function() {
    let flag = false; Iframe = document.createElement('iframe'),
    loadData = ()=> {
      if(flag) {// Read B's datalet data = iframe.contentWindow.name;    
        console.log(data, 66666);
        iframe.contentWindow.document.write(' ');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
      } else {
          flag = true; / / loaded with domain proxy files iframe. ContentWindow. Location = `${currentDomain}/proxy.html`; }}; iframe.src = `${corssDomain}/b-data.html`;
    if (iframe.attachEvent) {
      iframe.attachEvent('onload', loadData);
    } else {
      iframe.onload  = loadData;
    }
    document.body.appendChild(iframe);
  }
</script>
Copy the code

As can be seen from the figure above, A obtains the data from page B. How to say, it is too complicated, and it needs to add an iframe and also need A relay page. Therefore -> To sum up, personally, WINDOw. name is indeed A theoretical solution. Cross-domain must rely on various features of window.name, but must be done in the same browser window with iframe and in-domain paging.

HTML5 postMessage is a rumored successor

So this is kind of an advanced way. Why? Because the front of JSONP or window.name, is a fancy, somebody else’s official design it is not used for cross-domain or is to exploit the design of the loophole, as for CORS and NGINX are non-front-end category. So HTML5 came up with this postMessage specifically for doing “safe” cross-domain, can the difference between a son and a son be the same 😂? But I don’t know why, I think maybe it’s used less, maybe I don’t know, but I don’t see people using it.

Otherwindow.postmessage (message, targetOrigin, [Transfer]);

PostMessage relies on a reference to another window, which can be returned by window.open(), an iframe contentWindow, or a named indexed window.frames. So you’ll probably see postMessage and iframe used together in other places as well.

PostMessage is also relatively simple to use, and the official documentation is more detailed, interested can read it carefully, I directly here on the practice code:

/ / A pagelet opener;
function openB () {
    opener = window.open('http://127.0.0.1:3008/index.html'} // Send the messagefunction postMsg() {
    const msg = document.getElementById('chatB').value;
    opener.postMessage(msg, "HTTP: / 127.0.0.1:3008");
}
Copy the code

The logic of page A is very simple, that is, we use window.open() to open B through page A, and then use the obtained targetWindow to communicate between the two pages.

// B page window.adDeventListener ("message", receiveMessage, false);

functionReceiveMessage (event) {/ / Chrome browser compatibility const origin = event. The origin | | event. The originalEvent. Origin;if(origin ! = ="http://127.0.0.1:3006") {
      return; } const { data } = event; // Get the data from A // here is your logic... }Copy the code

On page B, we listen for the message event and determine if it is the target domain. If it is the target domain, we get the data and act on it.

Here I would like to emphasize why it is safe, because before A and B communicate, they will judge whether it is the target domain. If not, they will not operate, which is A state controlled by the front-end developer.

Let’s take a look at the effect:

Can only use A ah, good yo ~ to describe, since has completed A with B hair message, then send Buddha to the west, I put B to A also write, is also A simple version of the chat system.

OK, looks very good, after all, the official scheme, get very mature, and send data can also be a variety of formats, this should be the most advanced. But, forgive me, even after writing this little Demo, I still can’t imagine its real and appropriate use scenario, LAN chat? Possible, if you say real-time communication with me, that I certainly do not believe, because the following will also introduce more cattle big guy ~ if someone uses much, or real scene used, can leave a message to communicate, let me go up knowledge 😄

Other cross-domain solutions

document.domain

This is even less used, and only exists in books or documents, because the scene is more limited and restricted. His limitations were few, but very limited. To achieve cross-domain in this way, A and B must meet the following conditions:

A: http://aaa.xxx.com:port
B: http://bbb.xxx.com:port
Copy the code

That is, the level-1 domain name of A and B must be the same, but the level-2 domain name must be different. The protocol and port number must be the same.

Set window.domain = ‘xxx.com’ to each other to communicate… Forgive me for not having a domain name to show you. But the truth is not necessary, this way why…

WebScoket

Well, the real boss is here, come, above talk postMessage when, did A small Demo chat with B, also said, if it is really chat communication scenario, the boss level must be Webscoket ah.

Why can Websocket handle cross-domain?

How to put this question. First of all, putting websockets here is cheating. Why? Because when we say cross-domain, we mean that the browser and the server have the same origin restriction when they communicate over HTTP. Websocket is not based on HTTP at all. It is a browser communication protocol on top of TCP/IP, the same layer as HTTP.

Now write an article is too difficult, but also can draw 😂

Webscoket and HTTP are the same layer protocol, so HTTP restrictions on Webscoket, they don’t care about you, peer relationship, why do you care about me, but there is a little arrow, When WebSocket establishes a handshake connection (TCP three-way handshake), data is transmitted through HTTP. However, after the connection is established, the real data transmission stage does not need HTTP. About Websocket here will not involve too much, because this article is said to cross domain, since the above write a communication, then take Websoket also write a to see the difference, first effect picture (simple client and server chat) :

As you can see, the point of Websocket is not really to solve cross-domains, and in fact no one should use it to solve cross-domains. It is important in that it provides the ability for both the client and the server to push messages actively. If HTTP is used, the client usually initiates a request and the server responds to the request, but cannot actively push messages to each other. Therefore, if Websocket is not used, it is usually through a long rotation of AJAX and timer is set to continuously send requests to update data. This is a waste of performance and not very elegant. So the advantages of Websocket are summarized as follows:

  • No homology restriction, no cross domain
  • In full-duplex communication, both ends can actively push messages
  • Better real-time, more flexible

The application scenarios of Websocket are those applications with high real-time performance, such as communications, stock funds, bit-based applications.

I don’t know much about it, please check the official documentation and other relevant articles for more information.

Related topics

1. What is cross-domain and why

2. Talk about some ways to solve cross-domain problems

3. Talk about the implementation principle and process of JSONP

conclusion

Despite all the cross-domain solutions listed above, CORS and JSONP are actually the two most commonly used and frequently asked questions in interviews.

So compare CORS and JSONP:

CORS JSONP
advantages Relatively simple, both support post and support GET The use of native tag features, especially good compatibility
disadvantages Earlier versions of IE are incompatible Only get is supported, and front-end and back-end conventions are required

Write here cross-domain related practice summary is basically finished, very tired ah, because in addition to the principle of the scene to write code, it is not easy, I hope to help you ~

The code address is 👇 here

If you think it’s ok, please click “Star” and “like”.