不喜欢广告? 无广告 今天

服务器访问日志——你应用接收到的每一个请求的故事

更新于

服务器处理的每个HTTP请求都会在访问日志中留下一条记录。以下是逐字段解读日志内容的方法,以及需要关注的模式。

服务器访问日志——你的应用程序接收到的每一个请求的故事 1
广告 移除?

服务器处理的每一个HTTP请求都会在访问日志中留下一条记录。大多数情况下,这些文件会默默存储在磁盘上不断增长,直到触发磁盘警报或生产环境出现问题,这时大家突然都想要查看这些日志文件。

以下是运行组合日志格式的服务器中的一行日志:

203.0.113.42 - jsmith [09/May/2026:14:32:11 +0000] "GET /api/users/profile HTTP/1.1" 200 1843 "https://example.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

八个字段。每个字段都是关于发生了什么的证据。我们从左到右来看。

各个字段,逐一说明

1. 客户端IP — 203.0.113.42

打开与服务器TCP连接的IP地址。这通常是最终用户的IP地址。如果你位于负载均衡器、CDN或反向代理(例如,Nginx位于Node应用前面)之后,那么这个IP地址将是代理的IP地址。真实的客户端IP地址存在于请求头中——你需要明确配置日志格式以捕获这些信息。 不是 在Nginx中,这需要在你的 X-Forwarded-ForX-Real-IP 指令中添加

在Apache中,使用 $http_x_forwarded_for 。如果你跳过了这个步骤,然后收到滥用投诉或需要阻止某个恶意用户,你就会发现自己在每一条日志记录中都看到的是负载均衡器的IP地址。 log_format 2. Ident — %{X-Forwarded-For}i始终是一个连字符。这个字段原本用于携带identd查询的结果——一个古老的协议(RFC 1413),允许服务器询问客户端操作系统哪个进程正在发起连接。现在没有人再运行identd了。这个字段存在是因为在identd仍然流行时,通用日志格式被标准化了。可以忽略它。

3. 认证用户 — -

当使用HTTP基本认证或摘要认证时,该字段会填充用户名。对于大多数现代应用——如使用令牌认证、会话Cookie或JWT——这个字段通常为连字符。如果你使用htpasswd保护管理区域,失败的登录会显示为

,伴随401状态码;成功的登录则显示用户名。 jsmith

4. 时间戳 — - 服务器处理请求完成的时间(而不是开始时间)。格式为

。时区偏移量比人们意识到的更重要——如果你的应用服务器运行在UTC时间,但你的APM或告警工具位于本地时区,那么每次都需要进行时间转换才能将日志峰值与特定事件关联起来。建议所有时间都使用UTC。 [09/May/2026:14:32:11 +0000]

5. 请求行 — 包含信息最密集的字段。由三部分组成:HTTP方法、路径及查询字符串,以及协议版本。 — GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS。在端点上发现意外的方法值得特别注意。 day/Mon/year:HH:MM:SS timezone路径+查询字符串

——告诉你请求了什么内容。查询字符串可以包含搜索词、ID,以及在设计不佳的API中可能存在的认证令牌。请按此方式记录日志。 "GET /api/users/profile HTTP/1.1"

——2026年你的日志中出现的HTTP/1.0客户端,要么是古老的集成,要么是伪装成旧客户端的程序。如果服务器支持,HTTP/2和HTTP/3会以相应版本记录。

  • 方法 6. 状态码 —
  • 服务器返回的HTTP状态码。这是最终的判断字段。 ——成功。请求已处理。
  • 协议 ——重定向。客户端需要前往另一个位置。

——客户端错误。请求有误、缺少认证、未找到。可能是正常使用,也可能是探测行为。 200

——服务器错误。你的应用崩溃、超时或返回了错误内容。必须对这些情况进行调查。

  • 2xx 在处理事件时,首先按
  • 3xx 筛选。然后查看第一个500错误的时间点——那就是故障开始的时间。在此之前的内容是事件的前因,之后的内容是影响范围。
  • 4xx 7. 发送字节数 —
  • 5xx 响应体的大小(不包括头部)。连字符表示零字节(典型情况是

响应——客户端已经拥有内容)。在本应返回几百字节的端点上出现异常大的数值是一个警示信号。一个已认证用户访问“获取个人资料”端点却收到40MB的响应,要么是程序错误,要么是有人在滥用数据导出功能。 5xx 8. 引用来源 —

客户端在发出请求前所处的位置——浏览器的 1843

请求头中的URL。(HTTP规范在1996年拼错了,我们至今仍使用这个错误。)直接访问、书签和原生应用的请求会带有空的引用来源。这个字段仅存在于组合日志格式中;原始的通用日志格式在“发送字节数”处结束。 304 Not Modified 引用来源垃圾——大量伪造的引用来源头试图出现在你的分析数据中——过去较为常见,现在基本已成为历史。仍然建议从聚合统计数据中过滤掉这些内容。

9. 用户代理 — "https://example.com/dashboard"

客户端自我标识的信息。用户代理很容易被伪造,因此应将其视为提示而非事实。合法的爬虫通常会如实标识: Referer 。模仿浏览器的爬虫会发送完整的Mozilla/5.0 Chrome字符串。Curl发送

,除非有人用

覆盖它。需要关注的模式包括:相同用户代理字符串以机器速度持续击打相同端点,或一个声称是iOS Safari的用户代理却以人类浏览器不会出现的模式进行请求(没有图片、没有CSS、顺序访问产品页面爬取)。 "Mozilla/5.0 (Windows NT 10.0; Win64; x64)…"

在每条日志中出现的常见模式 Googlebot/2.1 (+http://www.google.com/bot.html), Bingbot/2.0漏洞扫描 curl/8.x 一个IP地址或小网段在短时间内快速访问数十个路径: -A.

。所有请求都返回404。这是一个自动化扫描器在运行检查清单,而不是有针对性的攻击。它们会持续扫描所有公网IP地址。

真正的问题不是“为什么他们在扫描我”——而是“这些路径中是否有任何一个返回了200”。如果

在你的服务器上返回200,那就是实际问题所在。

凭证填充攻击 /.env, /wp-login.php, /phpmyadmin, /admin/config.yml, /.git/config大量POST请求发送到登录端点,几乎全部返回401,来自多个不同的IP地址。关键特征是:相同的端点、一致的响应大小(错误页面)、多个源IP地址共享同一个AS编号。响应时间也相对稳定——自动化登录尝试以恒定速率进行,以避免被速率限制。

部署后404激增 /.env 你部署了一个新版本。404数量激增。旧邮件、书签和外部网站中的链接指向了已不存在的URL。这是正常现象——但如果404出现在本应存在于新版本中的URL上,那就是路由回归问题。请将404路径与你的路由定义进行比对。

# Check if any sensitive paths actually returned 200
grep -E '"(GET|POST) /(wp-login\.php|\.env|\.git/config|phpmyadmin|admin)' access.log | awk '$9 == 200'

响应速度聚集现象

标准日志格式不包含响应时间。你需要自行添加:在Apache中,在你的

# Count POST /login attempts with 401 status by source IP
awk '$6 == "\"POST" && $7 == "/api/login" && $9 == "401" {print $1}' access.log \
  | sort | uniq -c | sort -rn | head -20

指令后追加

(微秒);在Nginx中,添加 块。一旦你有了这个字段: 如果慢请求集中在某个特定时间窗口,那就是资源竞争——可能是定时任务、批量处理或备份正在猛烈地冲击数据库。如果某个路径在任何时间都持续缓慢,那就是一个慢查询或一个阻塞I/O调用,需要进行性能分析。

从日志中调试事件

访问日志是一条时间线。当用户报告“大约下午3点出了问题”时,你应该: %D 筛选出14:50到15:10的时间窗口 LogFormat查找第一个5xx错误——那就是问题开始的时间 $request_time 。如果你跳过了这个步骤,然后收到滥用投诉或需要阻止某个恶意用户,你就会发现自己在每一条日志记录中都看到的是负载均衡器的IP地址。 log_format 检查在几分钟前发生了什么变化:是否有部署?配置推送?证书更新?

# Nginx: show requests slower than 3 seconds (request_time in last field)
awk '{if ($NF+0 > 3) print $0}' /var/log/nginx/access.log | head -20

查看哪些路径出现了5xx错误——是所有路径还是仅一个端点?

检查成功响应前后发送字节数的变化——是否有响应开始被截断?

几个值得留意的失败特征:

  • 502激增
  • ——上游服务崩溃(应用服务器崩溃、连接池耗尽、数据库宕机)。502错误从一个精确的时间点开始。
  • 重定向循环
  • ——同一个IP地址反复将同一个路径重定向至301/302。通常是HTTPS重定向配置错误,或Cloudflare SSL设置与应用自身重定向逻辑冲突所致。
  • 200但字节数为零

——状态码为200,但发送字节数为0或

  • 。你的应用接收了请求,捕获了一个异常,却返回了一个空响应体。这是典型的未处理错误情况。 413激增
  • ——客户端发送的请求体超过了你的大小限制。要么你的限制设置过低,不符合实际使用场景,要么是有人在探测上传漏洞。 如果你处理的是多种格式的日志——Apache通用格式、Apache组合格式、Nginx默认格式、自定义格式——
  • 访问日志解析器 可以解析并注释字段,这样你每次切换服务器时就不必手动记忆字段位置。 -你将后悔未设置的日志管理
  • 日志轮转 配置为每日轮转、压缩,并保留14到30天。否则,日志文件会不断增长,直到磁盘空间耗尽。这种情况在生产环境中真实发生。

集中式日志管理 一旦你拥有多个服务器,逐个尾随日志文件就无法扩展。应将日志发送到Loki + Grafana、Elasticsearch或托管服务。结构化的JSON日志格式比使用awk解析CLF日志更容易进行查询。 原始日志的访问控制

日志文件可能包含带有令牌、用户敏感信息(PII)和内部路径的查询参数。不要让日志文件对所有人可读。如果你受GDPR或其他类似法规约束,必须谨慎设定日志保留周期。

  • 不要记录敏感查询参数logrotate ——如果你的应用接受认证令牌或密码作为URL参数(这本不该如此,但一些旧API仍如此),应在日志级别进行过滤,防止这些信息写入磁盘。 access.log 持续增长直到磁盘空间填满。这种情况在生产环境中会发生。
  • 集中式日志记录 — 当你拥有多个服务器时,逐个尾随日志文件是无法扩展的。将日志发送到Loki + Grafana、Elasticsearch或托管服务。结构化的JSON日志格式使得查询比使用awk解析CLF格式要容易得多。
  • 对原始日志进行访问控制 — 日志文件可能包含带有令牌、用户敏感信息(PII)和内部路径的查询参数。不要让它们对世界可读。如果你受GDPR或其他类似法规约束,必须谨慎考虑日志保留期限。
  • 不要记录敏感的查询参数 — 如果你的应用程序接受认证令牌或密码作为URL参数(这不应该发生,但某些旧版API确实如此),在日志级别对其进行过滤,防止它们写入磁盘。
想要享受无广告的体验吗? 立即无广告

安装我们的扩展

将 IO 工具添加到您最喜欢的浏览器,以便即时访问和更快地搜索

添加 Chrome 扩展程序 添加 边缘延伸 添加 Firefox 扩展 添加 Opera 扩展

记分板已到达!

记分板 是一种有趣的跟踪您游戏的方式,所有数据都存储在您的浏览器中。更多功能即将推出!

广告 移除?
广告 移除?
广告 移除?

新闻角 包含技术亮点

参与其中

帮助我们继续提供有价值的免费工具

给我买杯咖啡
广告 移除?