【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题

目录

  • 引言
  • [一、同源策略(Same-Origin Policy)概述](#一、同源策略(Same-Origin Policy)概述)
      • [1.1 同源策略的定义](#1.1 同源策略的定义)
      • [1.2 同源策略的作用](#1.2 同源策略的作用)
  • [二、CORS 的引入与工作原理](#二、CORS 的引入与工作原理)
    • [2.1 CORS(跨域资源共享)的基本概念](#2.1 CORS(跨域资源共享)的基本概念)
    • [2.2 简单请求与预检请求](#2.2 简单请求与预检请求)
      • [2.2.1 简单请求(Simple Requests)](#2.2.1 简单请求(Simple Requests))
      • [2.2.2 预检请求(Preflight Request)](#2.2.2 预检请求(Preflight Request))
    • [2.3 预检请求流程](#2.3 预检请求流程)
  • [三、CORS 相关 HTTP 头部](#三、CORS 相关 HTTP 头部)
    • [3.1 `Access-Control-Allow-Origin`](#3.1 Access-Control-Allow-Origin)
    • [3.2 `Access-Control-Allow-Methods`](#3.2 Access-Control-Allow-Methods)
    • [3.3 `Access-Control-Allow-Headers`](#3.3 Access-Control-Allow-Headers)
    • [3.4 `Access-Control-Allow-Credentials`](#3.4 Access-Control-Allow-Credentials)
    • [3.5 `Access-Control-Expose-Headers`](#3.5 Access-Control-Expose-Headers)
    • [3.6 `Access-Control-Max-Age`](#3.6 Access-Control-Max-Age)
  • 四、跨域请求的类型
    • [4.1 简单请求](#4.1 简单请求)
    • [4.2 预检请求](#4.2 预检请求)
  • 五、处理跨域问题的常见方式
    • [5.1 前端(JavaScript)处理 CORS](#5.1 前端(JavaScript)处理 CORS)
      • [5.1.1 使用 `fetch` 发起跨域请求](#5.1.1 使用 fetch 发起跨域请求)
      • [5.1.2 使用 `XMLHttpRequest` 发起跨域请求](#5.1.2 使用 XMLHttpRequest 发起跨域请求)
    • [5.2 Node.js 中处理 CORS](#5.2 Node.js 中处理 CORS)
      • [5.2.1 使用 `cors` 中间件](#5.2.1 使用 cors 中间件)
      • [5.2.2 使用自定义 CORS 头部](#5.2.2 使用自定义 CORS 头部)
    • [5.3 Python 中处理 CORS](#5.3 Python 中处理 CORS)
      • [5.3.1 安装 `Flask-CORS`](#5.3.1 安装 Flask-CORS)
      • [5.3.2 配置 CORS](#5.3.2 配置 CORS)
    • [5.4 Go 语言中处理 CORS](#5.4 Go 语言中处理 CORS)
      • [5.4.1 使用 `gorilla/handlers`](#5.4.1 使用 gorilla/handlers)
  • [六、CORS 处理流程图](#六、CORS 处理流程图)
  • [七、CORS 常见问题](#七、CORS 常见问题)
    • [7.1 `Access-Control-Allow-Origin` 设置问题](#7.1 Access-Control-Allow-Origin 设置问题)
    • [7.2. 预检请求失败](#7.2. 预检请求失败)
    • [7.3 带凭证的请求问题](#7.3 带凭证的请求问题)
    • [7.4 跨域请求的缓存问题](#7.4 跨域请求的缓存问题)
    • [7.5 使用代理解决跨域](#7.5 使用代理解决跨域)
  • 总结

引言

在现代 Web 开发中,跨域请求已经成为不可避免的一部分。浏览器的同源策略(Same-Origin Policy)虽然提供了基本的安全保障,但也限制了不同域之间的数据交互。为了弥补这一限制,CORS (Cross-Origin Resource Sharing,跨域资源共享)应运而生。CORS 是浏览器的一项安全机制,允许从一个域名(如前端页面的域)发起跨域请求,从而访问其他域名(如后端 API)的资源。通过这一机制,Web 应用可以灵活地访问跨域的资源,同时确保用户数据的安全。

本文将详细介绍 CORS 的工作原理、涉及的 HTTP 头部、跨域请求的不同类型以及如何在前后端开发中正确配置 CORS,帮助开发者更好地理解和解决常见的跨域问题。

一、同源策略(Same-Origin Policy)概述

1.1 同源策略的定义

浏览器的同源策略 (Same-Origin Policy)是一种重要的安全机制,用于阻止不同源(域)之间的恶意操作。根据同源策略,网页中的脚本只能访问与其所在网页相同源的资源。源的定义包括三个主要部分:

  • 协议(Scheme) :如 http://https://
  • 主机(Host) :如 www.example.comapi.example.com
  • 端口(Port) :如 808080

如果请求的协议、主机名或端口号不一致,浏览器将视为跨域请求,默认会阻止这样的访问。例如:

  • http://example.comhttps://example.com 属于不同来源(协议不同);
  • http://example.comhttp://api.example.com 属于不同来源(主机名不同);
  • http://example.com:80http://example.com:8080 属于不同来源(端口不同)。

1.2 同源策略的作用

同源策略的核心目的是保护用户的数据隐私和安全,避免恶意网站通过脚本发起未经授权的请求,从而窃取或篡改用户的数据。例如:

  • 一个恶意网站可能试图通过 JavaScript 脚本访问银行网站,获取用户的敏感信息如账户余额或信用卡号码。
  • 如果没有同源策略的保护,网站之间的数据交换将可能面临被恶意操控的风险。

二、CORS 的引入与工作原理

由于同源策略对跨域资源共享的限制,前端开发中常常需要访问不同域的资源,比如从 www.example.comapi.example.com 请求数据。为了能够安全、灵活地进行跨域通信,CORS(跨域资源共享)机制应运而生。

2.1 CORS(跨域资源共享)的基本概念

CORS(Cross-Origin Resource Sharing) 是一种机制,允许受限的资源在一个域(域A)上被另一个域(域B)请求。CORS 通过在 HTTP 请求中添加额外的头部信息来实现跨域通信,从而解决了浏览器的同源策略限制。

同源策略(Same-Origin Policy)

浏览器的同源策略(Same-Origin Policy)是一种用于防止不同来源的网页互相干扰的机制。它要求,网页中的脚本只能访问与它相同源的资源。换句话说,不同域名、协议或端口的资源访问会被浏览器默认阻止。

同源的定义:

  • 相同的协议(http:// 与 https://)
  • 相同的主机名(www.example.comexample.com
  • 相同的端口号(80与8080)

如果协议、主机名或端口号不相同,则被视为跨域请求。

CORS 的核心思想是,服务器通过在 HTTP 响应头中设置特定字段,来允许或拒绝跨域请求。CORS 并不改变浏览器的同源策略,而是通过配置来放宽限制。

2.2 简单请求与预检请求

根据请求类型,CORS 分为两种情况:简单请求预检请求

2.2.1 简单请求(Simple Requests)

简单请求是指那些符合以下条件的跨域请求:

  • 请求方法是 GETPOSTHEAD
  • 请求头部只包含以下字段之一:AcceptContent-Type(只限 application/x-www-form-urlencodedmultipart/form-datatext/plain),Authorization 等常见字段。

对于这种请求,浏览器会直接发送请求到服务器,并且不发送预检请求。

2.2.2 预检请求(Preflight Request)

如果跨域请求方法是 PUTDELETEPATCH,或者请求中包含自定义的 HTTP 头部(如 X-Custom-Header),浏览器首先会发送一个 OPTIONS 请求来询问服务器是否允许跨域请求。该请求被称为"预检请求"。服务器需要在响应中包含允许跨域访问的标识,浏览器才会继续发送实际的请求。

2.3 预检请求流程

在进行跨域请求时,浏览器通常会先发送一个预检请求(OPTIONS 请求)以确定服务器是否允许跨域访问。预检请求的流程如下:

  1. 浏览器发送 OPTIONS 请求 :浏览器向服务器发送一个 OPTIONS 请求,询问服务器是否支持跨域请求。
  2. 服务器响应 CORS 头部信息:服务器根据请求的内容,在响应头中添加 CORS 相关的字段,告知浏览器是否允许跨域请求。
  3. 判断是否允许跨域请求:浏览器根据服务器返回的 CORS 头部信息,判断是否允许继续发送实际的跨域请求。
  4. 发送实际请求或报错
    • 如果服务器允许,浏览器会继续发送实际请求。
    • 如果服务器不允许,浏览器会拒绝请求并抛出 CORS 错误。

是 否 CSDN @ 2136 浏览器发送 OPTIONS 请求 服务器响应 CORS 头部信息 是否允许跨域请求? 浏览器发送实际请求 浏览器拒绝请求, 提示 CORS 错误 服务器响应实际请求 浏览器处理并显示响应 CSDN @ 2136

说明

  1. 浏览器发送 OPTIONS 请求 :浏览器首先发送一个 OPTIONS 请求到服务器,以询问是否允许跨域请求。
  2. 服务器响应 CORS 头部信息 :服务器在响应中包含 Access-Control-Allow-Origin 等 CORS 相关头部,告知浏览器是否允许跨域。
  3. 判断是否允许跨域请求
    • 如果服务器允许跨域,浏览器会发送实际请求。
    • 如果服务器不允许,浏览器会拒绝请求,并报出 CORS 错误。
  4. 发送实际请求或拒绝
    • 如果允许,浏览器继续发出实际请求。
    • 如果不允许,浏览器会显示 CORS 错误。
  5. 服务器响应实际请求:如果跨域请求被允许,服务器会正常响应实际请求。
  6. 浏览器处理并显示响应:浏览器接收并处理服务器返回的数据,最后展示给用户。

通过上述流程,浏览器能够确保服务器允许跨域请求,从而安全地进行数据交换。

三、CORS 相关 HTTP 头部

CORS 主要依赖服务器端的 HTTP 头部来进行配置。以下是常见的 CORS 相关头部字段及其作用:

  • Access-Control-Allow-Origin:指定哪些源(域)可以访问资源。可以是单个源,或者是 *(允许所有源)。
  • Access-Control-Allow-Methods:指定允许的 HTTP 方法(如 GET, POST, PUT, DELETE 等)。
  • Access-Control-Allow-Headers:指定允许的请求头字段。
  • Access-Control-Allow-Credentials:指示是否允许发送凭据(如 cookies)到跨域资源。
  • Access-Control-Expose-Headers:允许客户端访问特定的响应头。
  • Access-Control-Max-Age:指示预检请求的有效期,即多少秒内无需再次发送预检请求。

3.1 Access-Control-Allow-Origin

  • 作用 :指定哪些源(域)可以访问该资源。可以是单个域名,也可以是 *,表示允许所有来源。
    • 单个域名:Access-Control-Allow-Origin: https://www.example.com
    • 允许所有来源:Access-Control-Allow-Origin: *
    • 如果允许的来源是动态的,服务器可以根据请求的 Origin 动态返回允许的域名。

3.2 Access-Control-Allow-Methods

  • 作用:指定允许的 HTTP 请求方法。
  • 常见值GET, POST, PUT, DELETE, PATCH

3.3 Access-Control-Allow-Headers

  • 作用 :指定哪些请求头字段可以包含在实际请求中。例如,某些自定义请求头,如 X-Custom-Header,需要通过这个字段允许。
  • 示例Access-Control-Allow-Headers: Content-Type, X-Custom-Header

3.4 Access-Control-Allow-Credentials

  • 作用 :指示是否允许发送凭据(如 cookies)。如果设置为 true,表示跨域请求中可以发送 cookies。
  • truefalse
  • 注意 :当设置为 true 时,Access-Control-Allow-Origin 不能为 *,必须指定具体的域名。

3.5 Access-Control-Expose-Headers

  • 作用:允许浏览器访问指定的响应头。默认情况下,浏览器只会暴露某些标准的响应头,使用该字段可以暴露其他自定义的头部。
  • 示例Access-Control-Expose-Headers: X-Response-Time

3.6 Access-Control-Max-Age

  • 作用:指定预检请求的有效期(单位为秒)。在此期间,浏览器不会再次发送预检请求。
  • 示例Access-Control-Max-Age: 3600 表示预检请求的结果有效期为 1 小时。

四、跨域请求的类型

4.1 简单请求

  • GETPOSTHEAD 方法
  • 头部字段限制:只允许常见的头部字段,如 AcceptContent-TypeAuthorization 等。

4.2 预检请求

  • 如果请求方法是 PUTDELETEPATCH,或者包含自定义头部字段,浏览器会先发送一个 OPTIONS 请求(预检请求)询问服务器是否允许跨域操作。

五、处理跨域问题的常见方式

以下分别展示在前端、Node.js、Python 和 Go 中处理跨域请求的代码示例,并对其进行详细说明。

5.1 前端(JavaScript)处理 CORS

在前端代码中,通常通过设置 fetchXMLHttpRequestmodecredentials 等选项来控制跨域行为。

5.1.1 使用 fetch 发起跨域请求

javascript 复制代码
fetch('https://example.com/data', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
  },
  // 是否允许携带 cookies
  credentials: 'include', // 'same-origin', 'include', 'omit'
})
.then(response => {
  return response.json();
})
.then(data => {
  console.log(data);
})
.catch(error => {
  console.error('Error:', error);
});
  • credentials: 'include':允许携带 cookies。如果目标服务器配置了 CORS 头部 Access-Control-Allow-Credentials: true,浏览器才会发送带有 cookies 的跨域请求。

5.1.2 使用 XMLHttpRequest 发起跨域请求

javascript 复制代码
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data', true);
xhr.withCredentials = true; // 设置是否带上凭证
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4 && xhr.status == 200) {
    console.log(JSON.parse(xhr.responseText));
  }
};
xhr.send();

5.2 Node.js 中处理 CORS

在 Node.js 中,处理 CORS 最常见的方式是使用 cors 中间件,它能简化 CORS 相关的配置。

5.2.1 使用 cors 中间件

首先,需要安装 cors

bash 复制代码
npm install cors

然后在代码中引入并使用它:

javascript 复制代码
const express = require('express');
const cors = require('cors');
const app = express();

// 使用 cors 中间件
app.use(cors({
  origin: 'https://your-frontend-domain.com', // 允许的来源
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true // 允许携带凭证
}));

app.get('/data', (req, res) => {
  res.json({ message: 'Hello World' });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

5.2.2 使用自定义 CORS 头部

如果不使用 cors 中间件,可以手动添加 CORS 头部:

javascript 复制代码
const express = require('express');
const app = express();

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://your-frontend-domain.com'); // 允许的源
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', 'true');
  next();
});

app.get('/data', (req, res) => {
  res.json({ message: 'Hello World' });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

5.3 Python 中处理 CORS

在 Python 中,可以使用 Flask-CORS 扩展来处理 CORS。

5.3.1 安装 Flask-CORS

bash 复制代码
pip install flask-cors

5.3.2 配置 CORS

python 复制代码
from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app, origins="https://your-frontend-domain.com", supports_credentials=True)

@app.route("/data")
def data():
    return {"message": "Hello World"}

if __name__ == "__main__":
    app.run(port=5000)

5.4 Go 语言中处理 CORS

在 Go 中,可以通过 gorilla/handlersnet/http 来处理 CORS。

5.4.1 使用 gorilla/handlers

首先安装 gorilla/handlers

bash 复制代码
go get github.com/gorilla/handlers

然后配置 CORS:

go 复制代码
package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/gorilla/handlers"
	"net/http"
)

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/data", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`{"message": "Hello World"}`))
	}).Methods("GET")

	// 配置 CORS
	headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"})
	originsOk := handlers.AllowedOrigins([]string{"https://your-frontend-domain.com"})
	methodsOk := handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE"})

	// 启动服务器
	http.ListenAndServe(":3000", handlers.CORS(originsOk, headersOk, methodsOk)(r))
}

六、CORS 处理流程图

是 否 成功 失败 CSDN @ 2136 前端请求资源 浏览器发送请求 浏览器检测是否跨域 是否跨域? 发送预检请求 OPTIONS 直接发送请求 服务器检查预检请求并返回 CORS 响应头 浏览器继续发送实际请求 浏览器阻止实际请求并报告错误 服务器处理请求并返回数据 浏览器接受响应 渲染页面 浏览器反馈 CORS 错误 CSDN @ 2136

解释

  • 前端请求资源:前端应用(例如一个网页)发出请求,可能会向不同的域、协议或端口请求资源,导致跨域。

  • 浏览器发送请求:浏览器会发起 HTTP 请求,向服务器请求所需资源。

  • 浏览器检测是否跨域:浏览器根据请求的目标 URL 判断请求是否跨域。如果目标 URL 与当前网页 URL 的域、协议或端口不同,则认为是跨域请求。

  • 是否跨域:这是判断跨域请求与否的关键节点。如果请求和当前页面的源不同,则会触发 CORS 机制。

    • 是跨域 :浏览器会发送一个预检请求(Preflight Request)。这是一个 HTTP 请求,用于询问目标服务器是否允许跨域访问,通常是一个 OPTIONS 请求。

    • 否跨域:如果请求没有跨域,浏览器会直接发送请求,不经过预检过程。

  • 发送预检请求(OPTIONS) :如果是跨域请求,浏览器会先发送一个 OPTIONS 请求,询问服务器是否允许跨域操作。

  • 服务器检查预检请求并返回 CORS 响应头 :服务器收到预检请求后,会根据 CORS 配置返回相应的 CORS 头部信息,如 Access-Control-Allow-Origin 和其他相关字段。如果服务器允许该请求,浏览器继续发送实际的请求。

  • 服务器处理请求并返回数据:如果预检请求成功,浏览器会发出实际的跨域请求。服务器处理请求并返回数据。

  • 浏览器接受响应:浏览器接收到响应后,会检查 CORS 头部,确认是否允许访问资源。如果允许,则进行页面渲染;如果不允许,则阻止该请求。

  • 渲染页面:如果响应没有问题,浏览器会将数据渲染到页面上,展示给用户。

  • 浏览器反馈 CORS 错误:如果预检请求失败,或者响应头中缺少必要的 CORS 信息,浏览器会终止请求并提示 CORS 错误。

七、CORS 常见问题

7.1 Access-Control-Allow-Origin 设置问题

No 'Access-Control-Allow-Origin' header is present on the requested resource :表示响应中缺少 Access-Control-Allow-Origin 头部。
描述

  • Access-Control-Allow-Origin 是 CORS 头部中的关键字段,用来指定允许跨域访问的来源(即允许哪些域名访问资源)。如果响应中没有该字段或该字段的值不匹配请求的来源,浏览器会阻止跨域请求。报错为:
    No 'Access-Control-Allow-Origin' header is present on the requested resource

解决方案

  • 服务器可以通过返回该头部来明确哪些域名被允许跨域访问。可以指定单一域名(如 https://example.com),或者使用通配符 * 允许所有域名访问,但通配符不能与带凭证的请求(如 cookies 或 Authorization 头部)一起使用,也不能与 credentials: 'include' 一起使用。
  • 如果多个域名都需要访问,服务器可以动态判断请求来源,并根据来源返回不同的 Access-Control-Allow-Origin 值。

示例

json 复制代码
Access-Control-Allow-Origin: https://example.com
  • 如果允许所有域访问:
json 复制代码
Access-Control-Allow-Origin: *

注意

  • 通配符 * 不能与带凭证的请求(例如 cookiesAuthorization)一起使用。如果请求需要凭证,服务器必须指定明确的来源(域名)。即 Access-Control-Allow-Origin 必须设置为明确的域名,而不能使用 *

7.2. 预检请求失败

描述

  • 对于某些复杂的请求(如 PUTDELETE,或包含自定义头部的请求),浏览器会首先发送一个 OPTIONS 预检请求,以确认服务器是否接受跨域请求。如果服务器没有正确响应或缺少必需的 CORS 头部,实际请求会被浏览器阻止。报错为:
    CORS policy: Response to preflight request doesn't pass access control check

解决方案

  • 服务器需要正确处理 OPTIONS 请求,并返回适当的 CORS 响应头。常见的响应头包括:
  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods(指定允许的 HTTP 方法,如 GET, POST, PUT, DELETE 等)
  • Access-Control-Allow-Headers(列出允许的自定义头部)

示例

json 复制代码
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization

7.3 带凭证的请求问题

描述

  • 当浏览器在请求中包含凭证(如 cookiesAuthorization 头部)时,CORS 请求需要显式的配置来允许凭证一起发送。如果服务器没有设置 Access-Control-Allow-Credentials,浏览器会拒绝携带凭证的请求。可能出现以下错误:
    Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'

解决方案

  • 当浏览器携带凭证(如 cookies 或 Authorization)发起跨域请求时,服务器需要在响应中设置 Access-Control-Allow-Credentials: true,并且 Access-Control-Allow-Origin 不能使用通配符(*),必须指定明确的域名。

示例

json 复制代码
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
  • 如果服务器允许携带 cookies 和其他凭证,但未正确配置 Access-Control-Allow-Credentials,浏览器将拒绝请求。

常见错误

  • No 'Access-Control-Allow-Origin' header is present on the requested resource:这通常意味着服务器没有正确设置 Access-Control-Allow-Origin 头部。

7.4 跨域请求的缓存问题

描述

  • 浏览器可能会缓存跨域请求的响应。如果 CORS 响应头设置不当,缓存可能导致不必要的跨域问题。

解决方案

  • 服务器可以通过设置 Cache-Control 头部,控制缓存策略。例如,可以禁用缓存:
json 复制代码
Cache-Control: no-store

示例

json 复制代码
Cache-Control: no-cache
Access-Control-Allow-Origin: https://example.com
  • 如果需要缓存响应,可以使用 no-cache,但仍需要确保正确设置 CORS 头部。

7.5 使用代理解决跨域

描述

  • 如果由于 CORS 设置问题而无法直接访问资源,可以通过设置一个代理服务器来转发请求,从而绕过跨域限制。代理服务器会代表客户端发起请求,并返回响应数据。

解决方案

  • 前端可以将请求发送到与页面同域的代理服务器,由代理服务器向目标服务器发起请求,再将响应返回给前端。

优点

  • 这种方式可以避免浏览器的 CORS 限制,但增加了额外的服务器端负担。

总结

CORS 是一种重要的浏览器安全机制,解决了不同源之间资源共享的问题。无论是在前端使用 fetch 或 XMLHttpRequest 发起请求,还是在后端使用中间件或手动设置响应头部,正确的 CORS 配置对于确保跨域请求的顺利进行至关重要。通过合理配置 CORS 相关头部,开发者可以有效避免常见的跨域问题,如头部设置不正确、预检请求失败、带凭证的请求问题等。

掌握 CORS 的核心原理与配置方法,不仅能帮助开发者顺利实现跨域资源共享,还能提高 Web 应用的安全性和用户体验。如果你在开发过程中遇到任何 CORS 配置上的挑战,随时可以寻求更多的帮助和解决方案。


相关推荐
y先森2 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy2 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189112 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿3 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡4 小时前
commitlint校验git提交信息
前端
虾球xz4 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇4 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒4 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员5 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐5 小时前
前端图像处理(一)
前端