news 2026/9/20 7:46:32

Docker安装与nginx反向代理实战:从零部署到避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker安装与nginx反向代理实战:从零部署到避坑指南

做后端这几年,我越来越确信一件事:很多看起来复杂的架构问题,一旦拆到容器层面,思路会清晰很多。今天这篇内容不端着讲原理,就做一件事——带你把 Docker 从零装好,再跑一个 nginx,并用它完成反向代理配置。中间会踩到哪些坑,我会按自己的实战经验提前标出来。适合刚接触容器、被各种配置文件绕晕的同学,也适合那些已经在服务器上手工编译过 nginx、受够了依赖地狱的老手。整个流程走下来,你能独立部署 nginx 静态站点,能看懂一份反向代理配置里每一项参数的含义,也能自己写出多服务场景下的 nginx 转发规则。顺便说一句,nginx 官方镜像比在服务器上手动编译安装省心太多,这也是我当年转用 Docker 的直接原因。

1. 安装 Docker 前,先把镜像和容器的关系搞明白

1.1 Docker 到底是什么,为什么用容器跑 nginx 更省心

如果你第一次接触 Docker,可以把它想象成一个“软件集装箱码头”。每条船、每个集装箱都是一个独立的镜像,集装箱里装着你应用运行所需的全部依赖:操作系统依赖库、配置文件、运行时环境。Docker 做的事情就是把这些集装箱搬运到任意一台安装了 Docker 引擎的服务器上,一键启动,运行结果完全一致。

传统方式部署 nginx 时,最常见的坑是系统环境不一致。你在自己电脑上写的配置,放到 CentOS 服务器上,可能因为 openssl 版本不同、nginx 编译参数不同、依赖库缺失,直接启动失败。而 nginx 官方镜像把编译好的二进制、运行库、默认配置全部打包好,你只需要拉下来跑起来,不用关心宿主机的系统环境。这就是容器相对于传统部署方式最核心的优势:环境一致性和快速交付。

1.2 三个核心概念:镜像、容器、仓库

很多新手把“镜像”和“容器”混为一谈,这会导致后面配置挂载、修改文件时完全找不着北。

  • 镜像(Image):一个只读的模板,包含了程序运行的一切文件和默认配置。它相当于一个“光盘”,烧录进去之后你不会去改它,而是基于它去创建实例。
  • 容器(Container):镜像的运行实例。每运行一次镜像,就会生成一个可写层,你在里面创建文件、修改配置、安装软件,都发生在这一层。容器可以启动、停止、删除,删掉之后再从一个新容器开始,就等于系统“恢复出厂设置”。
  • 仓库(Registry):存放镜像的中央仓库。最常用的是 Docker Hub,你可以把它理解成 npm 或 Maven 的公共仓库,不过里面放的是操作系统级别的打包产物。

理解这三个概念之后,后面所有命令都会变得很自然:从仓库拉取镜像到本地,基于镜像启动容器,在容器里修改配置,把数据目录通过挂载卷暴露给宿主机。这套逻辑搞通了,Docker 的基本盘就稳了。

2. 不同操作系统安装 Docker 的具体操作

2.1 Windows 系统安装 Docker Desktop

Windows 上安装 Docker 目前的主流方案是 Docker Desktop,它依赖 WSL2 后端。整体思路是:在 Windows 里跑一个轻量级 Linux 子系统,Docker 引擎运行在这个子系统中,Windows 上的命令行工具与它通信。

安装前先确认两件事:BIOS 里已经开启虚拟化(任务管理器性能页能看到“虚拟化: 已启用”);系统是 Win10 64 位专业版、企业版或教育版,Win11 则更加流畅。接着去 Docker 官网下载 Docker Desktop 安装包,安装过程中默认勾选“Use WSL 2 instead of Hyper-V”,等待安装完成。

如果你发现官方安装包下载速度很慢,可以留意国内云厂商或软件镜像站提供的 Docker Desktop 安装包镜像,下载后检查文件哈希与官方一致再安装。装完启动 Docker Desktop,首次启动会自动初始化 WSL2 内核,稍等片刻,界面上提示 Docker Engine 已运行,就说明安装成功。这类桌面工具的问题大多集中在 WSL2 内核版本过低,遇到“WSL 2 installation is incomplete”错误时,去微软官方文档更新一下 WSL2 内核补丁即可。

2.2 Linux 系统安装 Docker Engine

Linux 服务器上安装 Docker,很多人会图省事直接用发行版仓库里的 docker.io 包,但那个版本经常比较旧。我的建议是用 Docker 官方源安装。Ubuntu 和 Debian 系的典型流程是这样:

# 安装工具包,配置官方 apt 源 sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release # 添加 Docker 官方 GPG 密钥和软件源 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 docker-ce sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io

CentOS / RHEL 系的流程类似,只是包管理器换成 yum,然后通过 systemctl 管理:

sudo systemctl enable --now docker

安装完成之后,一定要执行一个操作:把当前用户加入 docker 用户组,这样不用每次敲命令都加 sudo。

sudo usermod -aG docker $USER

然后退出终端重新登录,让用户组变更生效。这一步如果漏了,后面跑 docker 命令都会报 permissions 错误,而很多新手会以为是 Docker 坏了,实际上只是当前用户没有访问 docker.sock 的权限。

2.3 配置镜像加速源,解决下载慢的问题

几乎所有刚装完 Docker 的人都遇到过同一个尴尬:拉取 nginx 镜像时进度条半天不走,或者直接超时。这很可能不是网络断线,而是默认镜像仓库的连通性不稳定。解决办法是配置镜像加速源,也就是 registry mirror。

Linux 环境下,编辑或创建 /etc/docker/daemon.json:

{ "registry-mirrors": [ "https://你的加速地址" ] }

然后重启 Docker 服务使配置生效:

sudo systemctl daemon-reload sudo systemctl restart docker

Windows 版的 Docker Desktop 更简单:打开 Settings,进入 Docker Engine 标签页,把 JSON 里的 registry-mirrors 字段填好,点击 Apply & Restart。注意:加速地址建议到各家云厂商开发者文档里找最新的,这类地址变化较快,不同区域可用性也不一样。配置完可以用 docker info 命令查看 Registry Mirrors 是否成功列出,看到了就说明已生效。

2.4 验证安装是否成功的两个命令

装完任何环境,第一件事是验证。先看版本信息:

docker version

能看到 Server 部分的输出,说明 Docker 引擎正常运行。如果只有 Client 部分而 Server 连接失败,多半是 Docker daemon 没启动,或者当前用户没权限访问 socket。

再跑一次经典 hello-world:

docker run hello-world

这条命令会从仓库拉取一个极小的镜像,然后打印一段欢迎信息。它能正常输出,意味着 Docker 的拉取、镜像创建、容器运行完整链路已经通了。到这里,环境准备工作就告一段落。

3. Docker 镜像与容器基础操作,这里都是高频命令

3.1 最常用的十个 Docker 命令

Docker 命令很多,但日常开发用到频率最高的就一小撮。我把它们按使用场景分组:

  • 镜像相关:docker pull 拉取镜像,docker images 查看本地镜像,docker rmi 删除镜像,docker build 构建镜像。
  • 容器相关:docker run 创建并启动容器,docker ps 查看运行中的容器(加 -a 查看全部),docker start / stop / restart 控制容器启停,docker rm 删除容器,docker exec 进入容器执行命令。
  • 日志与状态:docker logs 查看容器输出,docker stats 查看资源占用,docker inspect 查看容器详细配置。

举个例子,拉取 nginx 镜像并启动一个测试容器,一条命令就能完成:

docker run -d --name webserver -p 8080:80 nginx:alpine

这条命令里 -d 表示后台运行,--name 给容器命名,-p 把容器的 80 端口映射到宿主机 8080 端口。然后浏览器访问 http://localhost:8080,就能看到 nginx 默认欢迎页。如果看不到,先看容器是否启动成功:docker ps -a,再看看日志:docker logs webserver。排查顺序一定是先看状态、再看日志。

3.2 端口映射与挂载卷:容器和宿主机沟通的两座桥

容器本身是一个隔离环境,宿主机默认无法直接访问容器内的端口,文件也不能直接读写容器内部的数据。所以需要两座“桥”:端口映射和挂载卷(volume)。

端口映射解决的是网络访问问题。语法是 -p 宿主机端口:容器端口。比如 nginx 容器内部监听 80,我们想用宿主机 80 访问,就写 -p 80:80。如果想多个 nginx 同时跑,可以分别映射到 8080、8081 等不同宿主机端口。

挂载卷解决的是数据持久化问题。容器一旦被删除,容器内创建的文件就全部丢失,这是容器设计使然。为了让配置文件、日志、业务数据在容器重建后依然保留,我们会把宿主机的目录映射到容器内部:-v /宿主机路径:/容器路径。挂载目录是 Docker 实战里最值得花时间理解的一个知识点,因为 nginx 部署、MySQL 数据存储、Redis 持久化,全都要依靠它。

3.3 强制删除、进入容器、拷贝文件这些细节操作

容器状态不同,删除命令也不一样。运行中的容器直接 docker rm 会报错,需要先 docker stop 再删除,或者用 docker rm -f 强制删除。这在做 nginx 配置调整、想快速重建容器时非常常用,我一般都直接用 -f 参数省一步操作。

进入容器内部有两种常用方式:

docker exec -it webserver sh

注意:nginx 官方镜像基于 Debian 或 Alpine,默认没有 bash,所以用 sh。如果想在容器里执行单条命令,比如测试 nginx 配置是否正确,可以直接写:

docker exec webserver nginx -t

另一个细节是容器和宿主机之间拷贝文件:

docker cp 本地文件路径 容器名:/容器路径 docker cp 容器名:/容器路径 本地文件路径

docker cp 适合临时改一下容器里的文件,但不建议作为常态化配置手段。因为容器重建之后拷贝进去的东西就没了,长期运维仍然推荐用挂载卷来管理配置。

4. 用 Docker 部署 nginx 静态站点,从拉镜像到挂目录

4.1 拉取 nginx 镜像并启动第一个容器

nginx 官方镜像有两个常见标签:nginx:latest 和 nginx:alpine。alpine 镜像基于 Alpine Linux,体积小很多,约 25MB,适合生产环境使用;latest 基于 Debian,包更全,适合需要调试的场景。入门阶段我建议直接上 alpine,体积小、启动快,出问题的面也小。

启动一个静态站点服务,完整命令如下:

docker run -d \ --name nginx-web \ -p 80:80 \ -v /data/project1:/usr/share/nginx/html/project1 \ -v /data/nginx/conf.d:/etc/nginx/conf.d:ro \ nginx:alpine

这条命令做了三件事:后台启动一个名为 nginx-web 的容器;把宿主机的 80 端口映射到容器 80 端口;把两个宿主机目录分别挂载到容器的静态文件目录和配置目录。其中 conf.d 挂载加了 :ro 后缀,意思是容器内这个目录只读,防止容器内部误改配置。这个细节容易忽略,但能让配置管理更可控。

4.2 nginx 配置文件在容器里的位置,这个必须记牢

很多人在容器里找 nginx 配置时晕头转向,因为镜像里的路径和手工编译安装的路径不一样。基于官方镜像,关键路径如下:

  • 主配置:/etc/nginx/nginx.conf
  • 自定义站点配置:/etc/nginx/conf.d/ 目录下,默认有一个 default.conf
  • 静态文件根目录:/usr/share/nginx/html
  • 日志文件:/var/log/nginx/access.log 和 error.log

重点是:nginx.conf 主程序里默认有一行 include /etc/nginx/conf.d/*.conf; 这意味着你要添加新站点,不需要改主配置,只要在 conf.d 目录下放一个以 .conf 结尾的文件,再重载 nginx 即可。这个设计让多站点管理非常清爽。

修改配置两种方式:一是进容器直接改,适合临时验证;二是宿主机写好,通过挂载卷映射进去,这才是长期项目的推荐做法。后面所有配置文件我都放在宿主机目录里,再挂载进容器,容器一旦出问题可以随时重建,配置不会丢。

4.3 一台 nginx 挂多个项目目录,别再走错路

需求场景很常见:一个服务器上部署了前端项目 A 和 B,想共用同一个 nginx,通过不同路径区分,比如 /proj1 和 /proj2。做法就是给每个项目准备一个目录,全部挂载进去。

docker run -d \ --name nginx-web \ -p 80:80 \ -v /data/www/project1:/usr/share/nginx/html/project1 \ -v /data/www/project2:/usr/share/nginx/html/project2 \ -v /data/nginx/conf.d:/etc/nginx/conf.d:ro \ nginx:alpine

然后在 conf.d 目录下的配置文件里写好 location 规则:

server { listen 80; server_name _; location /proj1/ { alias /usr/share/nginx/html/project1/; index index.html; } location /proj2/ { alias /usr/share/nginx/html/project2/; index index.html; } }

这里有一个高频坑:location 里用了 alias 还是 root。root 会拼接完整路径,alias 则是直接替换 location 匹配部分。用 root 加项目路径时,nginx 会去 /usr/share/nginx/html/project1/proj1 找文件,很容易出现 404。我在最初写静态站时就在这里栽过,改成 alias 之后立刻正常。

5. nginx 反向代理实战配置,把请求转发给后端服务

5.1 先搞清楚反向代理在这条链路里扮演的角色

反向代理这个词的字面意思容易让人绕晕。我换个说法:它就是一个“前台接待员”。你访问某个域名或端口,前台接待员根据请求路径,决定把请求转给后面的哪个业务部门。比如访问 /api,转给后端 Java 服务;访问 /admin,转给管理后台;访问 /,返回静态页面。

在 Docker 场景下,反向代理还有额外的妙用:容器之间通过内部网络互相访问,外部客户端只能访问映射出来的端口。nginx 作为整个服务群的统一入口,只需要对外暴露一个 80/443 端口,内部再按规则转发到各个容器的对应端口。这样做的好处是安全、灵活,多个服务复用一套 TLS 证书、一套访问控制策略,非常符合实际生产环境的要求。

5.2 一份可以直接抄作业的 nginx 反向代理配置

假设我们有一个后端服务运行在容器的 8080 端口,服务名是 app1,还有一个静态前端站点。要用 nginx 做转发,配置写在 /data/nginx/conf.d/reverse.conf 里,内容如下:

server { listen 80; server_name api.example.com; location / { proxy_pass http://app1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } server { listen 80; server_name www.example.com; root /usr/share/nginx/html; index index.html; }

解释一下关键参数:proxy_pass 指定转发目标地址,这里用的是容器名 app1 加端口 8080,前提是 nginx 和后端服务在同一个 Docker 网络里;proxy_set_header 是转发时补齐请求头,否则后端应用拿不到真实的客户端 IP,日志统计会有偏差,部分依赖 HTTPS 协议判断的应用也容易出问题。

配置文件写好后,测试语法并重载:

docker exec nginx-web nginx -t docker exec nginx-web nginx -s reload

nginx -t 用来检查语法,输出 syntax is ok 再重载,这一步能避免绝大多数配置错误引起的服务中断。

5.3 多服务、多域名反向代理怎么扩展

真实项目里往往不止一个后端服务。管理后台、用户端 API、文件服务,每个都想用独立的域名或路径访问。这时只需要在 conf.d 目录下多建几个 server 块,或者在同一个 server 块里按 location 分开处理。

多数网友问我最多的问题就是 location 路径匹配规则。简单记忆:

  • 精确匹配:location = /login,优先级最高,常用于精准拦截。
  • 前缀匹配:location /api/,当请求路径以 /api/ 开头时命中。
  • 正则匹配:location ~ .php$,按正则表达式匹配,优先级低于精确匹配,高于普通前缀匹配。
  • 默认匹配:location /,兜底处理所有未命中的请求。

例如把 API 和静态文件放在同一个域名下:

server { listen 80; server_name example.com; location /api/ { proxy_pass http://app1:8080; proxy_set_header Host $host; } location /files/ { alias /data/files/; } location / { root /usr/share/nginx/html; index index.html; } }

这里有一个容易踩的坑:proxy_pass 后面是否带路径,带不带会影响转发规则。带路径时,比如 proxy_pass http://app1:8080/,nginx 会用完整的原始请求路径替换掉 location 前缀;不带路径时,nginx 保持原始 URI 不变。具体行为有细微差别,建议有疑问时先打日志确认实际请求路径。

5.4 用 Docker Compose 编排 nginx 加多个应用服务

手动 docker run 跑一堆容器,还要自己创建网络、串联依赖,命令会越来越长。这时引入 Docker Compose,它用一份 YAML 文件描述所有服务,一条 docker compose up -d 就能把整个服务群全部拉起。

下面是 nginx 加两个后端服务的示例 docker-compose.yml:

services: nginx: image: nginx:alpine container_name: nginx-web ports: - "80:80" volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro - ./html:/usr/share/nginx/html depends_on: - app1 - app2 app1: image: myapp1:latest container_name: app1 expose: - "8080" app2: image: myapp2:latest container_name: app2 expose: - "8081"

注意几个细节:app1 和 app2 使用的 expose 关键字只暴露端口给 Docker 内部网络,并不映射到宿主机,这样外部无法直接访问后端服务,只能通过 nginx 转发;nginx 里的 proxy_pass 直接写 http://app1:8080 和 http://app2:8081,因为 Compose 默认会在同一个网络里建立服务名的 DNS 解析。这个设计既清晰又安全,是我在本地开发最常用的组合。

6. 常见问题排查与避坑记录,这些我全踩过

6.1 镜像拉取慢、超时怎么办

镜像拉取慢,除了配置镜像加速源之外,还有两个容易被忽略的原因。一是在大陆网络下直接拉取 Docker Hub 官方镜像速度不稳定,此时优先检查 registry-mirrors 是否生效;二是拉取的镜像体积过大,比如 nginx:latest 有 190MB,而 nginx:alpine 只有约 25MB,如果只是跑服务没必要拉臃肿版本。

如果加速地址不生效,可以执行 docker info 查看 Registry Mirrors 字段下方是否列出了你配置的地址。没列出来大概率是 daemon.json 语法错误,或者 Docker Desktop 的配置没有 Apply。改完配置后,docker systemctl restart docker,或者 Docker Desktop 里点 Restart,千万不要省略重启步骤。

6.2 端口被占用怎么处理

启动容器时报错 bind: address already in use 是最常见的端口冲突。处理步骤很简单:先找到占用端口的进程,然后决定是停掉该进程还是给容器换端口。

sudo lsof -i :80 # 或者 sudo netstat -tunlp | grep :80

如果 80 端口被系统已有的 nginx 或 Apache 占用,建议先停掉宿主机自带的 Web 服务,或者把 Docker 容器映射到另一个端口,比如 -p 8080:80。另外注意容器停止后端口会自动释放,如果停掉了容器但端口依然占用,考虑是不是有多个同名容器在跑,用 docker ps -a 查一下。

6.3 改了配置文件为什么始终不生效

这个问题八成出在挂载路径上。容器内配置文件路径和宿主机挂载路径不匹配,你在宿主机改了文件,容器里看到的还是旧内容。排错时先进入容器确认实际内容:

docker exec nginx-web cat /etc/nginx/conf.d/reverse.conf

如果文件内容没有变化,问题基本可以断定是挂载卷没生效。检查 docker run 或 docker-compose.yml 里的 volumes 字段,确保宿主机路径是绝对路径,或者相对路径相对于 compose 文件而言正确。还有一种情况:配置文件修改正确,但忘记重载 nginx。每次修改完 conf 文件后都养成执行 nginx -t && nginx -s reload 的习惯,能省掉大量无效排查时间。

6.4 反向代理出现 403 或 502 的排查思路

反向代理报 403 和 502 的含义完全不同,排查方向也要分开。

403 Forbidden 常见原因有三个:一是静态文件目录权限不足,容器内 nginx 用户无法读取挂载目录,修复方法是让宿主机目录至少对其他用户有 r-x 权限;二是没有 index 文件,nginx 默认查找 index.html 找不到时直接报错;三是 location 匹配到了禁止访问的规则,比如 deny all。

502 Bad Gateway 则说明 nginx 成功收到了请求,但转发目标不可达。按顺序检查:后端容器是否在运行(docker ps);服务名和端口是否写对(容器间通信要用服务名而非 localhost);两个容器是否在同一个 Docker 网络(Compose 自动建网,手动 run 需要加入相同网络);后端服务本身是否启动成功(docker logs 后端容器)。我见过最多的错误就是把 proxy_pass 写成了 http://localhost:8080,在容器内 localhost 指向的是 nginx 容器自己,自然无法访问后端。

6.5 日志怎么看,容器日志和 nginx 日志别搞混

容器日志和 nginx 业务日志是两回事。docker logs nginx-web 输出的是容器主进程的标准输出,nginx 官方镜像把 access.log 和 error.log 都软链接到了 /dev/stdout 和 /dev/stderr,所以能直接看到访问日志。

但如果你有一个容器内挂载了自定义日志目录,docker logs 就不会包含业务日志。此时需要去宿主机挂载目录看文件。建议在排查问题的时候先 docker logs 看启动和访问情况,如果信息不够,再进容器或用挂载日志分析。线上问题排查,日志永远比别人告诉你的经验更接近真相。

6.6 给刚入门的人几个实在建议

第一,不要试图记住所有命令。记不住 docker run 的参数不是问题,工程上没人靠背命令干活,而是靠文档和模板。把一份能用的 docker run 和 docker-compose.yml 保存在自己的代码库里,需要时改一改。第二,容器命名要有规律。我有段时间给容器起名 nginx1、新的容器 nginx2,最后根本分不清哪个挂载了哪份配置。后来统一按“服务名-用途-序号”的方式命名,配合 docker ps 的 --format 参数输出可读列表,管理起来清晰得多。第三,生产环境尽量少用 docker run 裸启动,凡是要长期运行的服务都交给 Compose 或更上层的编排工具。裸启动的命令很难追溯,别人接手时完全不知道这些容器是怎么来的,配置文件又是哪一份。把这些可复现的东西统一交给 docker-compose.yml 管理,才是一个可持续维护的方案。

我个人在实际操作中的体会是,Docker 最大的价值不是让你记住多少命令,而是把你从“环境能不能跑”这件事里解放出来。nginx 反向代理只是第一步,等你熟悉这套流程之后,MySQL、Redis、Node 服务都能用同样的方式快速编排起来。真遇到配不明白的地方,先去看日志,日志永远比配置文件诚实。希望这篇文章能帮你少走几段弯路,也希望你装好 Docker、跑起 nginx 之后,能像我当初一样由衷觉得:早知道容器这么省事,真该早点用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 7:43:39

可复现、可追溯、可协作:搭建个人开放研究工作流

做研究和写代码不一样的地方在于,写代码有个明确的对错,跑不通就是跑不通;而研究工作里头大量环节都是模糊的:今天读了一篇文献,觉得某个思路可行,第二天换个状态可能又推翻了自己。如果这个过程中间不留下…

作者头像 李华
网站建设 2026/9/20 7:40:14

MaaS+ComfyUI:游戏美术外包团队的云端生产管线实战

做游戏美术外包这行有个心照不宣的痛点:甲方要得越来越急,预算却一砍再砍。我们团队去年尝试本地部署ComfyUI,显卡买了一批,环境却天天坏,几台机器各自为政,最后变成谁会用谁去碰的玩具。后来我索性把整套流…

作者头像 李华
网站建设 2026/9/20 7:39:09

深入解析换行符:\r、\n、\r\n、\n\r的区别与工程实践

1. 换行符这件事,远比你想的复杂很多人第一次被换行符坑到,是在做数据清洗的时候。从数据库导出一份 CSV,用 Excel 打开一切正常,结果用脚本一读,每行末尾多出一个诡异的空行;或者从网页表单里复制一段文本…

作者头像 李华