No more trouble for back-end classmates to deal with cross-domain issues

No more trouble for back-end students to deal with cross-domain issues

What is cross-domain

Whenever we open the console after requesting backend identification, if No Access-Control-Allow-Origin’ header is present on the requesting resource appears, then this article may help you.

Cross-domain means that in a web page, when a web page tries to access resources under different domain names (such as sending Ajax requests, using iframe to load other web pages, etc.), it will be restricted by the same-origin policy, thus A situation where data cannot be obtained normally.

What is the Same Origin Policy

The same source refers to two URLs with the same protocol, domain name, and port.

For example: If you are making a request from domain1.com/api to domain1.com, the request will go through.

image.png

If a request is made to another domain, www.domain2.com/api, the browser will block the request.

image.png

Why do browsers need cross-domain

The reason why browsers restrict cross-domain access is for security reasons.

If browsers do not restrict cross-origin access, attackers can forge requests to access sensitive user information on other websites or perform malicious actions.

Take a simple example:

Assume that victim logs in his account on website A, and attacker publishes a link on website B to trick users into clicking. The link points to a malicious website C, which Website C uses JavaScript code to initiate a cross-domain request to website A, stealing victim‘s sensitive information on website A (such as cookies, usernames, passwords, etc.).

An attacker can embed the following code into website C, and use the XMLHttpRequest object to initiate a cross-domain request to website A:

var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.domain2.com/user-info", true);
xhr.onreadystatechange = function() {
  if (xhr. readyState == 4) {
    alert(xhr. responseText);
    // Upload the obtained sensitive information to the attacker's server
    //...
  }
}
xhr. send();

This code is executed on website C, and a cross-domain request is made to website A, and the sensitive information of the victim on website A is stolen. The attacker can upload the acquired information to their own server for illegal purposes, such as posing as the victim to log in to website A, stealing account funds, etc.

Therefore, if cross-domain access can break the same-origin policy, it will pose a great threat to personal privacy and property security. In order to protect the security of users, browsers restrict cross-domain access.

How to handle it gracefully

Whenever we encounter this problem, the fastest solution is to call the backend to add enable cors, so is there any frontend that can solve it by itself?

There are three commonly used methods:

  1. JSONP
  2. agent way
  3. Webpack devserver

JSONP

In the vernacular, JSONP is a technology that uses GET requests of script tags to achieve cross-domain technology. A simple case of JSONP:

Suppose we have a website A and want to get the data of another website B, but B and A are not in the same domain, so they cannot be accessed directly.

On the server side of B website, an interface named getData is provided, which can return some data. In order for A website to obtain these data, B website encapsulates it in a callback function named callback when returning the data, and uses the parameters of the callback function as required The data is sent to A network. Website A uses JSONP to obtain data from website B, and specifies a callback function named handleResponse.

The code for returning data from the backend of website B is as follows:

var data = {<!-- -->
  "name": "Alice",
  "age": 18
};
var callback = req.query.callback; // Get the name of the callback function
res.send(callback + '(' + JSON.stringify(data) + ')'); // Encapsulate the data in the callback function and return

The front-end request code of A website is as follows:

function handleResponse(data) {
  console. log(data);
}

var script = document.createElement('script');
script.src = 'http://www.domain2.com/getData?callback=handleResponse';
document.head.appendChild(script);

The advantage of JSONP is that it can realize cross-domain requests and has good compatibility, which is supported by almost all browsers. But it also has some disadvantages:

  1. Only GET requests are supported. Because JSONP implements cross-domain requests by dynamically creating script tags, and script tags only support GET requests.
  2. Data format restrictions. JSONP can only return data in JSON format, but cannot return data in XML format.

Proxy method

To put it bluntly, is to set up a local server by yourself, and bypass the same-origin policy of the browser by accessing the relationship between the server and the server.

I built a simple proxy with Nest.js:

import { Controller, Post, Req, Res, Body } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Request, Response } from 'express';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Controller()
export class AppController {
  constructor(private readonly httpService: HttpService) {}

  @Post('/api')
  proxy(
    @Req() request: Request,
    @Res() response: Response,

    @Body() data: any,
  ): Observable<any> {
    const url = request. query. url as string;
    const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
    return this.httpService.post(url, data, { headers }).pipe(
      map((res) => {
        response. send(res. data);
      }),
    );
  }
}

In the above code, we use the @Body() decorator to get the requested data and pass it as a parameter to the this.httpService.post() method. At the same time, use request.query to get the address of the request. When the request is successful, the response data is returned to the client through the response.send() method.

The principle is shown in the figure below:

image.png

Webpack devserver

If it is a large project and webpack is configured.

1. You can add the devServer.proxy property in the Webpack configuration file to implement cross-domain proxying. The specific implementation is as follows:

// webpack.config.js

module.exports = {<!-- -->
  //...
  devServer: {<!-- -->
    proxy: {<!-- -->
      '/api': {<!-- -->
        target: 'http://www.domain2.com', //requires a cross-domain url
        changeOrigin: true,
        pathRewrite: {<!-- -->
          '^/api': ''
        }
      }
    }
  }
}

In the above code, /api will be forwarded to www.domain2.com

Note that if changeOrigin is set to true in the proxy configuration, the Host field in the request header will be automatically set to the domain name of the proxy target when proxying the request, so that the same-origin policy of the browser can be bypassed and cross-domain requests can be realized .

2. When initiating a request in the application, set the path of the API request to the proxy address:

axios.get('/api/data')
  .then(response => {
    console. log(response. data)
  })
  .catch(error => {
    console. log(error)
  })

The pit you stepped on

It is worth noting that: When we go to the client to request the front-end own server, we also need to set up cross-domain, because the port number of the request is different.

End

If the friends passing by find it useful, please like and save it.