Technology Sharing

Thoroughly understand front-end cross-domain

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

 

Table of contents

1 Browser's Same Origin Policy

1.1 Overview of Same-Origin Policy

1.2 What is an origin?

2 What are the restrictions on cross-domain

2.1 Restrict DOM access

2.2 Restricting Cookie Access

2.3 Limit Ajax data acquisition

3. Some points to note

4CORS solves Ajax cross-domain problem

4.1CORS Overview

4.2CORS solves simple cross-domain requests

4.3 Simple and complex requests

4.4CORS solves complex cross-domain requests

4.5 Quickly complete configuration with the cors library

5JSONP solves cross-domain issues

6Configure proxy to solve cross-domain

6.1 Configure your own proxy server

6.2 Use Nginx to build a proxy server

6.3 Build a server with scaffolding


Code address git clone https://gitee.com/childe-jia/cross-domain-test.git

1 Browser's Same Origin Policy

1.1 Overview of Same-Origin Policy


The same-origin policy is a policy followed by browsers to ensure resource security, which imposes some restrictions on access to resources.
W3C's description of the same-origin policy:Same origin policy

1.2 What is an origin?


1. Components of a source

image.png


2 In the table below, only the two sources in the last row are the same.

Source 1

Source 2

Is it homologous?

http://www.xyz.com/home

https://www.xyz.com/home

⛔ Non-homologous ️

http://www.xyz.com/home

http://mail.xyz.com/home

⛔ Non-homologous

http://www.xyz.com:8080/home

http://www.xyz.com:8090/home

⛔ Non-homologous

http://www.xyz.com:8080/home

http://www.xyz.com:8080/search

✅Same source︎

 

3 Same-origin requests

image.png


4 Non-same-origin requests

image.png


5 Summary: The "source" and "target source" are inconsistent, which is "non-same source", also known as "heterogeneous source" or "cross-domain"

2 What are the restrictions on cross-domain


For example, if there are two sources: "Source A" and "Source B", and they are "non-same-origin", then the browser will have the following restrictions:

2.1 Restrict DOM access

Scripts from "Source A" cannot access the DOM of "Source B".

  1. <!-- <iframe id="framePage" src="./demo.html"></iframe> -->
  2. <iframe id="framePage" src="https://www.baidu.com"></iframe>
  3. <script type="text/javascript" >
  4. function showDOM(){
  5. const framePage = document.getElementById('framePage')
  6. console.log(framePage.contentWindow.document) //同源的可以获取,非同源的无法获取
  7. }
  8. </script>

2.2 Restricting Cookie Access

Source A cannot access the cookies of Source B

  1. <iframe id="baidu" src="http://www.baidu.com" width="500" height="300"></iframe>
  2. <script type="text/javascript" >
  3. // 访问的是当前源的cookie,并不是baidu的cookie
  4. console.log(document.cookie)
  5. </script>

2.3 Limit Ajax data acquisition

"Source A" can send requests to "Source B", but cannot obtain the response data from "Source B".

  1. const url = 'https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc'
  2. let result = await fetch(url)
  3. let data = await result.json();
  4. console.log(data)

Note: Among the above limitations, the browser's limitation on Ajax data acquisition is the most influential one and is often encountered in actual development.

3. Some points to note

  • 1Cross-domain restrictions only exist on the browser side, and there are no cross-domain restrictions on the server side.
  • 2 Even if it is cross-domain, Ajax requests can be sent normally, but the response data will not be given to the developer.
  • 3<link> , <script>、<img>...... 这些标签发出的请求也可能跨域,只不过浏览器对标签跨域不做严格限制,对开发几乎无影响

image.png

4CORS solves Ajax cross-domain problem

4.1CORS Overview

CORS stands for Cross-Origin Resource Sharing, which is a set of specifications for controlling browsers to verify cross-origin requests. The server adds specific response headers to control browser verification in accordance with the CORS specification. The general rules are as follows:
●If the server explicitly rejects cross-domain requests or does not indicate so, the browser verification will fail.
●If the server explicitly allows cross-domain requests, the browser verification will pass.
Note: Using CORS is the most orthodox way to solve cross-domain problems, and requires the server to be "our own".


4.2CORS solves simple cross-domain requests

The overall idea is: when the server responds, it adds the Access-Control-Allow-Origin response header to explicitly allow a certain source to initiate a cross-domain request, and then the browser passes it directly during verification.

image.png

The core code of the server (taking the express framework as an example):

  1. // 处理跨域中间件
  2. function corsMiddleWare(req,res,next){
  3. // 允许 http://127.0.0.1:5500 这个源发起跨域请求
  4. // res.setHeader('Access-Control-Allow-Origin','http://127.0.0.1:5500')
  5. // 允许所有源发起跨域请求
  6. res.setHeader('Access-Control-Allow-Origin','*')
  7. next()
  8. }
  9. // 配置路由并使用中间件
  10. app.get('/',corsMiddleWare,(req,res)=>{
  11. res.send('hello!')
  12. })

4.3 Simple and complex requests

CORS divides requests into two categories: ① simple requests and ② complex requests.

Simple request

Complex Requests

✅Request method: GET, HEAD, POST

1 is either a simple request or a complex request.
2 Complex requests will automatically send a preflight request.

✅The request header field must comply with《CORS Security Specification》
Note: As long as you do not modify the request header manually, it can generally comply with this specification.

✅The value of Content-Type in the request header can only be the following three:
●text/plain
●multipart/form-data
●application/x-www-form-urlencoded

About preflight request:

  • 1 Sending time: The preflight request is sent before the actual cross-domain request and is automatically initiated by the browser.
  • 2Main function: used to confirm with the server whether the next cross-domain request is allowed.
  • 3 Basic process: First initiate an OPTIONS request. If it passes the pre-check, continue to initiate the actual cross-domain request.
  • 4. Request header content: An OPTIONS pre-check request usually contains the following request header:

Request Header

meaning

Origin

The source of the request

Access-Control-Request-Method

The actual HTTP method requested

Access-Control-Request-Headers

Custom headers used in the actual request (if any)

4.4CORS solves complex cross-domain requests

1 Step 1: The server passes the browser's pre-check request, and the server needs to return the following response header:

Response Headers

meaning

Access-Control-Allow-Origin

Allowed Origins

Access-Control-Allow-Methods

Allowed methods

Access-Control-Allow-Headers

Allowed custom headers

Access-Control-Max-Age

Preflight request result cache time (optional)

image.png

2 Step 2: Process the actual cross-domain request (same as processing a simple cross-domain request)

image.png

Server core code:

  1. // 处理预检请求
  2. app.options('/students', (req, res) => {
  3. // 设置允许的跨域请求源
  4. res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
  5. // 设置允许的请求方法
  6. res.setHeader('Access-Control-Allow-Methods', 'GET')
  7. // 设置允许的请求头
  8. res.setHeader('Access-Control-Allow-Headers', 'school')
  9. // 设置预检请求的缓存时间(可选)
  10. res.setHeader('Access-Control-Max-Age', 7200)
  11. // 发送响应
  12. res.send()
  13. })
  14. // 处理实际请求
  15. app.get('/students', (req, res) => {
  16. // 设置允许的跨域请求源
  17. res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
  18. // 随便设置一个自定义响应头
  19. res.setHeader('abc',123)
  20. // 设置允许暴露给客户端的响应头
  21. res.setHeader('Access-Control-Expose-Headers', 'abc')
  22. // 打印请求日志
  23. console.log('有人请求/students了')
  24. // 发送响应数据
  25. res.send(students)
  26. })

4.5 Quickly complete configuration with the cors library

In the above configuration, you need to configure the response header yourself, or you need to manually encapsulate the middleware yourself. With the help of the cors library, you can complete the configuration more conveniently.

●Install cors

npm i cors

●Simple configuration of cors

app.use(cors())

●Fully configure cors

  1. // cors中间件配置
  2. const corsOptions = {
  3. origin: 'http://127.0.0.1:5500', // 允许的源
  4. methods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'], // 允许的方法
  5. allowedHeaders: ['school'], // 允许的自定义头
  6. exposedHeaders: ['abc'], // 要暴露的响应头
  7. optionsSuccessStatus: 200 // 预检请求成功的状态码
  8. };
  9. app.use(cors(corsOptions)); // 使用cors中间件

By default, js cannot access the response headers set by the backend, so the backend needs to be exposed

5JSONP solves cross-domain issues

1JSONP Overview: JSONP is a protocol that uses<script>标签可以跨域加载脚本,且不受严格限制的特性,可以说是程序员智慧的结晶,早期一些浏览器不支持 CORS 的时,可以靠 JSONP 解决跨域。


2Basic process:

  • ○Step 1: The client creates a<script>标签,并将其src属性设置为包含跨域请求的 URL,同时准备一个回调函数,这个回调函数用于处理返回的数据。
  • ○Step 2: After receiving the request, the server encapsulates the data in the callback function and returns it.
  • ○Step 3: The client's callback function is called, and the data is passed to the callback function in the form of parameters.

3 diagrams:

image.png

4 Code Example:

  1. <button onclick="getTeachers()">获取数据</button>
  2. <script type="text/javascript" >
  3. function callback(data){
  4. console.log(data)
  5. }
  6. function getTeachers(url){
  7. // 创建script元素
  8. const script = document.createElement('script')
  9. // 指定script的src属性
  10. script.src= 'http://127.0.0.1:8081/teachers'
  11. // 将script元素添加到body中触发脚本加载
  12. document.body.appendChild(script)
  13. // script标签加载完毕后移除该标签
  14. script.onload = ()=>{
  15. script.remove()
  16. }
  17. }
  18. </script>

5. jQuery encapsulated jsonp

?callback=?' is a fixed format and will be automatically parsed

  1. $.getJSON('http://127.0.0.1:8081/teachers?callback=?',(data)=>{
  2. console.log(data)
  3. })

6Configure proxy to solve cross-domain

6.1 Configure your own proxy server

There is no cross-domain problem between servers. You need to use express to start static resources to ensure that your server and the page are under the same origin.

  1. // 启动静态资源 让服务器跟页面同一个源
  2. app.use(express.static("./public"));

Configure proxy with http-proxy-middleware

  1. const { createProxyMiddleware } = require('http-proxy-middleware');
  2. app.use('/api',createProxyMiddleware({
  3. target:'https://www.toutiao.com',
  4. changeOrigin:true,
  5. pathRewrite:{
  6. '^/api':''
  7. }

 

advantage:

  • Rich in functions: http-proxy-middleware provides a wealth of configuration options to meet various proxy needs.
  • Multiple proxies can be flexibly configured: multiple proxy servers can be configured, corresponding to different interface paths.
  • Requests can be intercepted: Requests can be intercepted and modified through custom processing functions.

shortcoming:

  • The configuration is relatively complex: you need to understand the configuration rules and parameters of the http-proxy-middleware library.
  • Not suitable for production environment: http-proxy-middleware is mainly used in development environment and not suitable for production environment.

scenes to be used:

  • Suitable for front-end projects using any build tool and can be used with any development server.
  • Applicable to scenarios that require flexible configuration of multiple proxy servers.
  • Applicable to scenarios where requests need to be intercepted and modified.

6.2 Use Nginx to build a proxy server

The overall idea is to let nginx play two roles: a static content server and a proxy server.

Modify the nginx configuration as follows. Note that the root directory of nginx should not be the C drive.

  1. # 配置nginx根目录
  2. location / {
  3. root D:dist;
  4. index index.html index.htm;
  5. }
  6. # 配置代理
  7. location /dev/ {
  8. # 设置代理目标
  9. proxy_pass http://sph-h5-api.atguigu.cn/;
  10. }

2 Modify the front-end project so that all requests are forwarded to /dev and then repackaged

  1. const request = axios.create({
  2. baseURL:'/dev',
  3. timeout:10000
  4. })

Then you can directly access the nginx server. For example, if nginx is running on port 8099, access

http://localhost:8099

Then you will encounter the refresh 404 problem, add nginx configuration to solve it

  1. # 配置nginx根目录
  2. location / {
  3. root D:dist;
  4. index index.html index.htm;
  5. try_files $uri $uri/ /index.html; # 解决刷新404
  6. }
  7. # 配置代理
  8. location /dev/ {
  9. # 设置代理目标
  10. proxy_pass http://sph-h5-api.atguigu.cn/;
  11. }

Adding these two "/" removes dev

6.3 Build a server with scaffolding

1. Use the vue.config.js file to configure the proxy:

Create a vue.config.js file in the root directory of the Vue project and add the following code:

  1. module.exports = {
  2. devServer: {
  3. proxy: {
  4. '/api': {
  5. target: 'http://api.example.com',
  6. changeOrigin: true,
  7. pathRewrite: {
  8. '^/api': ''
  9. }
  10. }
  11. }
  12. }
  13. }

In the above code, we usedevServerConfiguration items to configure the proxy server.proxyProperties are used to configure the proxy rules./apiIndicates the interface path that needs to be proxied.targetThe property represents the target server address of the proxy.changeOriginThe property indicates whether to change the source address of the request.pathRewriteProperty is used to rewrite the request path.

advantage:

  • Simple configuration: Using the proxy configuration of webpack-dev-server, you only need to make simple configuration in the webpack configuration file.
  • Comprehensive features: webpack-dev-server provides a wealth of configuration options to meet most proxy needs.
  • Requests can be intercepted: Requests can be intercepted and modified through custom processing functions.

shortcoming:

  • Need to restart the server: After the configuration is modified, you need to restart webpack-dev-server for it to take effect.
  • Not suitable for production environments: webpack-dev-server is mainly used in development environments and is not suitable for production environments.

scenes to be used:

  • Applicable to front-end projects built with webpack, and use webpack-dev-server to start the development server.
  • Applicable to scenarios that require simple proxy configuration and do not need to modify the proxy configuration frequently.