Origin of cross-domain problems

The root cause of the cross-domain problem is the same origin policy of the browser, which prevents websites or loaded scripts from interacting with other websites. This effectively prevents malicious files and protects users’ security.

According to the same-origin policy, only two pages with the same protocol protocol, host name, and port number can interact with each other. Any difference between the two pages may cause cross-domain problems

In fact, even if the cross-domain ajax request is not intercepted, it is successfully sent to the server. The server normally processes the request and returns the resource. When the browser receives the resource, it finds that the current web page has a different source from the requested address and refuses to pass the resource returned by the server to the code. So the cross-domain problem is browser-specific and has nothing to do with the network request

Restrictions on the same-origin policy

If the two pages have different sources

  1. Unable to readcookie,localstorage,IndexedDB
  2. Unable to obtain or manipulate another sourceDOM
  3. Unable to sendajaxrequest

Cross-domain solutions

JSONP is cross-domain

JSONP is a simple way for a server to communicate with a client. The main principle is cross-domain access using the SRC attribute of the Script tag

In simple terms, the server sends a request to the page by adding a script tag. When the server receives the request, the data is returned in the specified callback parameter

Jsonp only supports GET requests (script tags are GET requests) but does not support post, PUT and other requests

// Server configuration
// Simply build a server with Express
const express = require('express');
const app = express();

app.get('/'.(req, res) = > {
  // Retrieve the function name and corresponding data from query
  const callback = req.query.callback;
  const name = req.query.name || "hello world";
  res.send(`${callback}('${name}') `);
  res.end();
})
// Listen on port 3000
app.listen(3000.() = > {
  console.log("listen 3000");
});
Copy the code
<! -- Front-end code -->
<h1 id="test"></h1>
<script>
  function sendAjax(name) {
    // Define a callback name (optional)
    const callback = "doSomething"
    // Define this function globally
    window[callback] = function (data) {
      document.querySelector('#test').innerHTML = data;
      // Remove it after use
     delete window[callback];
    }
    // Create a script tag, set SRC, and add it to head
    const script = document.createElement('script');
    script.src = `http://localhost:3000? name=${name}&callback=${callback}`;
    document.head.appendChild(script);
    // Remove the script tag
    document.head.removeChild(script);
  }
  sendAjax("123");
</script>
Copy the code

Cors is cross-domain

CORS is a cross-domain solution based on HTTP1.1, its full name is cross-Origin Resource Sharing, cross-domain Resource Sharing.

The general idea is that if a browser wants to access a server’s resources across domains, it needs permission from the server.

Cors specifies several different interaction modes for different requests

  1. A simple request
  2. Complex request (need to send precheck request first)

A simple request

Simple request judgment

  1. The request method is one of the following
  • get
  • post
  • head
  1. The request header contains only security fields, common security fields
  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type(Can only be the following valuestext/plain,multipart/form-data,application/x-www-form-urlencoded)

If the above conditions are met, the request is considered simple.

Simple request interaction

  1. Add to the request headeroriginfield

For example on the page http://127.0.0.1:5500 there is the following code causing cross-domain

// Different port numbers cause cross-domain problems
fetch("http://127.0.0.1:3000");
Copy the code
<! Connection: keep-alive Host: localhost:3000... Origin: http://127.0.0.1:5500 Referer: http://127.0.0.1:5500/index.htmlCopy the code

The Origin field tells the server which source address is on the requesting server

  1. Contains in the server response headerAccess-Control-Allow-Originfield

After receiving a request, the server checks the origin field in the request header. To Allow Access, add the access-Control-allow-Origin field to the response header

  • * : allows access from any source
  • Specific source: for examplehttp://127.0.0.1:5500Indicates that only the current source is allowed to access

Complex request interaction

When the browser decides that this is not a simple request, it follows these steps

  • The browser first sends an opption request, asking the server if it will allow it
  • The server judges and allows access
  • The browser sends a real request
  • The server completes the actual response

For example on the page http://127.0.0.1:5500 there is the following code causing cross-domain

fetch("http://localhost:3000/test", {
  / / post method
  method: "post".// Customize the request header
  headers: {
    name: "Nt"."content-type": "application/json"
  },
  / / request body
  body: JSON.stringify({name:"CORS"})})Copy the code
  1. The browser sends a precheck request
Access-control-request-headers: content-type,name access-Control-request-method: POST Connection: keep-alive Host: localhost:3000 ... Origin: http://127.0.0.1:5500 Referer: http://127.0.0.1:5500/index.htmlCopy the code

Precheck requests the purpose of precheck requests is to ask the server whether to allow subsequent real requests. It contains information about subsequent real requests. All precheck requests have the following characteristics

  • The request method isOPTIONS
  • No request body
  • The request header contains
    • origin: Indicates the source of the request
    • Access-Control-Request-Headers: Indicates the request header that will be changed in subsequent actual requests
    • Access-Control-Request-Method: a way to follow up a real request
  1. Server permit

After receiving the precheck request, the server can check the information in the request. If the access is allowed, the server responds as follows

. Access-Control-Allow-Headers: content-type,name Access-Control-Allow-Method: POST Access-Control-Allow-Origin: http://127.0.0.1:5500...Copy the code

For precheck requests, the degree of service does not need to respond to any message body, just in the response header

  • Access-Control-Allow-Headers: Request header that allows real request changes
  • Access-Control-Allow-Method: request method that allows real requests
  • Access-Control-Allow-Origin: Represents the source to which access is allowed, as in a simple request
  1. The browser sends the real request, and the server responds to the real request

After prechecking the request, the browser sends the real request, and subsequent requests are treated the same as simple requests

// Implement simple CORS manually
// Use the Express framework again

// Define a middleware
app.use((req, res, next) = > {
  // If the request method is options, the request is a complex request
  if (req.method.toLocaleLowerCase() === "options") {
    // Read the relevant information in the request header
    const nextHead = req.headers['access-control-request-headers'];
    const nextMethod = req.headers['access-control-request-method'];
    // Once you have the information, you can make some judgments
    res.setHeader('Access-Control-Allow-Headers', nextHead);
    res.setHeader('Access-Control-Allow-Method', nextMethod);
  }
  // Simple request
  // The Origin field needs to be configured for both simple and complex requests
  // Get origin from the request header
  const nextOrigin = req.headers.origin;
  // Let's go ahead and do it
  res.setHeader('Access-Control-Allow-Origin', nextOrigin);
  next();
})
Copy the code

Websocket is cross-domain

WebSocket is a new protocol in HTML5, which supports persistent connection and solves the defect that HTTP communication can only be initiated by the client.

How to establish a Websocket connection

The client negotiates an upgrade protocol with the WebSocket server through HTTP requests. After the upgrade, subsequent data exchanges follow the WebSocket protocol. There are some characteristic fields in the request header

<! -- Indicates that the protocol needs to be upgraded.
Connection: Upgrade
<! -- Request extension -->
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
<! Sec-websocket-accept: sec-websocket-accept: sec-websocket-accept
Sec-WebSocket-Key: A+C1VOMnuprTFHwx7R0bUA==
<! -- Websocket version -->
Sec-WebSocket-Version: 13
<! Update to WebSocket protocol
Upgrade: websocket
Copy the code

The server receives a return

Connection: Upgrade
<! Sec-websocket-key -->
Sec-WebSocket-Accept: 2zJTRh8A8UEc9ZttNOE9ilY73gg=
Upgrade: websocket
Copy the code

Follow-up requests are sent through Websocket. Websocket does not have cross-domain problems and does not require any additional configuration for cross-domain access

Nginx proxy

Nginx acts as a reverse proxy server that forwards HTTP requests to another or several servers. Cross-domain access is achieved by mapping a local URL prefix to the Web server to be accessed cross-domain.