YAML 在现代基础设施中无处不在:Kubernetes 清单文件、GitHub Actions 工作流、Docker Compose、Ansible Playbook、Helm Charts。它也是最容易悄无声息出错的格式——两个空格变成三个、冒号漏掉、裸字符串被隐式转换为布尔值,这些错误都不会在编辑器里报警,直到部署失败或运行时报出奇怪的 panic 才暴露出来。在线 YAML 验证工具让你在问题进入流水线之前就把它消灭。

立即验证 YAML →

为什么 YAML 验证如此重要?

YAML 解析器出了名的宽容。格式错误的 YAML 文件往往不会抛出异常,但解析出来的数据结构却与预期完全不同。

更危险的是 YAML 1.1(PyYAML、众多 Kubernetes 工具直到近年都在使用)的隐式类型转换:

settings:
  debug: yes        # 被解析为布尔 true,不是字符串 "yes"
  version: 1.0      # 被解析为浮点数,不是字符串
  country: NO       # 挪威国家代码——被解析为布尔 false!
  octal: 0777       # 被解析为八进制整数 511,不是字符串 "0777"

带类型预览的验证工具会明确显示每个值被解析成了什么类型,彻底消除这类意外。

YAML 核心语法

标量(Scalar)

string: Hello World
quoted_string: "Hello\nWorld"  # 支持转义序列
single_quoted: 'No escape \n here'  # 字面反斜杠
integer: 42
float: 3.14
boolean_true: true
boolean_false: false
null_value: null
multiline: |
  第一行
  第二行
  第三行
folded: >
  这几行
  会被拼接
  成一行。

|(字面块)保留换行符,>(折叠块)将换行替换为空格。

序列(列表)

# 块样式(最常用)
fruits:
  - apple
  - banana
  - cherry

# 流样式(紧凑写法)
colors: [red, green, blue]

映射(对象)

# 块样式
server:
  host: localhost
  port: 8080
  tls: true

# 流样式
point: {x: 1, y: 2}

嵌套结构

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    environment:
      - NGINX_HOST=example.com
    volumes:
      - ./html:/usr/share/nginx/html:ro
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret

锚点与别名(DRY)

YAML 通过锚点(&)和别名(*)避免重复:

defaults: &defaults
  adapter: postgres
  encoding: utf8
  pool: 5

development:
  <<: *defaults
  database: myapp_development

production:
  <<: *defaults
  database: myapp_production
  pool: 20

<<: 合并键会将引用的锚点展开到当前映射中。

多文档文件

单个 YAML 文件可以包含多个用 --- 分隔的文档:

---
kind: Deployment
metadata:
  name: web
---
kind: Service
metadata:
  name: web-svc

常见 YAML 错误

缩进错误

YAML 使用空格(永远不是 Tab)表示层级,且同一层级的缩进必须一致:

# 错误——缩进不一致
server:
  host: localhost
    port: 8080  # 过度缩进,触发解析错误

# 正确
server:
  host: localhost
  port: 8080

键名后缺少冒号

# 错误
server
  host: localhost

# 正确
server:
  host: localhost

未引用含冒号的字符串

# 错误——解析器会把这当成键值对
message: Error: something went wrong

# 正确
message: "Error: something went wrong"

使用了 Tab 字符

# 错误——YAML 禁止用 Tab 缩进
server:
	host: localhost  # Tab 字符导致解析错误

重复键

# 技术上无效,但大多数解析器静默接受
config:
  timeout: 30
  timeout: 60  # 覆盖第一个值,不报错

YAML 1.1 布尔值陷阱

# YAML 1.1(PyYAML、Ruby Psych < 4.0)中这些都是布尔值:
# true: true, True, TRUE, yes, Yes, YES, on, On, ON
# false: false, False, FALSE, no, No, NO, off, Off, OFF

country_code: NO   # 解析为 false,不是字符串 "NO"
enabled: yes       # 解析为 true——通常没问题,但让人意外

# 安全做法:对有歧义的值始终加引号
country_code: "NO"

YAML 1.2 消除了大部分这类隐式转换。了解你的工具链用的是哪个版本。

在 CI/CD 中验证 YAML

yamllint

yamllint 是标准的 Python YAML 检查工具:

pip install yamllint
yamllint config.yaml

自定义配置(.yamllint):

extends: default
rules:
  line-length:
    max: 120
  truthy:
    allowed-values: ['true', 'false']
    check-keys: false
yamllint -c .yamllint .  # 检查仓库中所有 YAML 文件

GitHub Actions 集成

name: Lint YAML
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: 安装 yamllint
        run: pip install yamllint
      - name: 检查 YAML 文件
        run: yamllint .

Pre-commit 钩子

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/adrienverge/yamllint
    rev: v1.35.1
    hooks:
      - id: yamllint
        args: [-c=.yamllint]

各语言解析 YAML

Python

pip install pyyaml
import yaml

# 用 safe_load 防止任意代码执行
with open('config.yaml', 'r') as f:
    config = yaml.safe_load(f)

print(config['server']['host'])

# 通过捕获异常验证
try:
    with open('config.yaml', 'r') as f:
        data = yaml.safe_load(f)
    print("YAML 格式正确")
except yaml.YAMLError as e:
    print(f"YAML 错误:{e}")

Node.js

npm install js-yaml
const yaml = require('js-yaml');
const fs = require('fs');

try {
  const config = yaml.load(fs.readFileSync('config.yaml', 'utf8'));
  console.log(config);
} catch (e) {
  console.error('YAML 格式错误:', e.message);
}

Go

go get gopkg.in/yaml.v3
package main

import (
    "fmt"
    "log"
    "os"

    "gopkg.in/yaml.v3"
)

type Config struct {
    Server struct {
        Host string `yaml:"host"`
        Port int    `yaml:"port"`
    } `yaml:"server"`
}

func main() {
    data, err := os.ReadFile("config.yaml")
    if err != nil {
        log.Fatal(err)
    }

    var config Config
    if err := yaml.Unmarshal(data, &config); err != nil {
        log.Fatalf("YAML 格式错误:%v", err)
    }

    fmt.Printf("Host: %s, Port: %d\n", config.Server.Host, config.Server.Port)
}

YAML vs JSON vs TOML 对比

特性YAMLJSONTOML
注释支持(#不支持支持(#
多行字符串支持(|>需转义 \n支持
锚点/别名支持不支持不支持
类型推断隐式(危险)显式严格
基于缩进
允许 Tab不适用
解析歧义高(1.1)/ 低(1.2)
冗余度

YAML 的核心优势是人类可读性强、冗余低。主要风险是隐式类型转换和基于缩进的敏感解析。机器生成的配置(API 响应、构建产物)优先用 JSON;人工编写的带注释配置,YAML 和 TOML 都是好选择——TOML 的歧义更少。

在线 YAML 验证工具

不想在本地安装工具?ZeroTool 的 YAML 验证器完全在浏览器内运行,全程不上传任何数据:

  • 精确到行列的 YAML 语法错误报告
  • 解析后的结构树形预览
  • 一键导出为 JSON
  • 100% 本地处理

立即使用 YAML 验证器 →