<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Archive for 2025-10 on chengzhycn&#39;s blog</title>
		<link>https://blog.jinzhi.site/posts/2025-10/</link>
		<description>Recent content in Archive for 2025-10 on chengzhycn&#39;s blog</description>
		<generator>Hugo</generator>
		<language>en-us</language>
		
		
		
		
			<lastBuildDate>Thu, 30 Oct 2025 12:18:28 +0800</lastBuildDate>
		
			<atom:link href="https://blog.jinzhi.site/posts/2025-10/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>APISIX 插件体系</title>
				<link>https://blog.jinzhi.site/posts/2025-10/apisix-%E6%8F%92%E4%BB%B6%E4%BD%93%E7%B3%BB/</link>
				<pubDate>Thu, 30 Oct 2025 12:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-10/apisix-%E6%8F%92%E4%BB%B6%E4%BD%93%E7%B3%BB/</guid>
				<description>&lt;h2 id=&#34;背景知识&#34;&gt;背景知识&lt;/h2&gt;&#xA;&lt;p&gt;APISIX 基于 Openresty 和 Nginx 开发，了解 APISIX 的插件体系也有必要先了解下 Nginx 和 Openresty 的基础知识。&lt;/p&gt;&#xA;&lt;h3 id=&#34;nginx-请求处理阶段&#34;&gt;Nginx 请求处理阶段&lt;/h3&gt;&#xA;&lt;p&gt;Nginx 将一个 HTTP 请求的处理过程精心划分为一系列有序的阶段（Phases），就像一个工厂的流水线。每个阶段都有特定的任务，不同的模块可以将自己的处理程序（handler）注册到感兴趣的阶段。这种设计使得 Nginx 的功能高度模块化、可扩展，并且处理流程非常清晰高效。&lt;/p&gt;&#xA;&lt;p&gt;一个请求在 Nginx 中主要会经过以下 &lt;strong&gt;11 个处理阶段&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;h4 id=&#34;1ngx_http_post_read_phase请求读取后阶段&#34;&gt;1. &lt;code&gt;NGX_HTTP_POST_READ_PHASE&lt;/code&gt; (请求读取后阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 接收到完整的请求头（Request Header）之后，第一个被执行的阶段。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块&lt;/strong&gt;: &lt;code&gt;ngx_http_realip_module&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 在这个阶段，&lt;code&gt;realip&lt;/code&gt; 模块会根据 &lt;code&gt;X-Forwarded-For&lt;/code&gt; 或 &lt;code&gt;X-Real-IP&lt;/code&gt; 等请求头，将客户端的真实 IP 地址替换掉代理服务器的 IP 地址。这对后续的访问控制和日志记录至关重要。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;2ngx_http_server_rewrite_phaseserver-级别地址重写阶段&#34;&gt;2. &lt;code&gt;NGX_HTTP_SERVER_REWRITE_PHASE&lt;/code&gt; (Server 级别地址重写阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 在 &lt;code&gt;server&lt;/code&gt; 配置块中执行 URL 重写。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;rewrite&lt;/code&gt; 指令（当它定义在 &lt;code&gt;server&lt;/code&gt; 块中时）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 在请求进入具体的 &lt;code&gt;location&lt;/code&gt; 匹配之前，对 URL 进行全局的、初步的改写。例如，将所有 &lt;code&gt;http&lt;/code&gt; 请求强制重定向到 &lt;code&gt;https&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;listen&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;server_name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;example.com&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 这个 rewrite 就工作在 SERVER_REWRITE 阶段&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;rewrite&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;^/(.*)&lt;/span&gt;$ &lt;span class=&#34;s&#34;&gt;https://example.com/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;permanent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;3ngx_http_find_config_phase配置查找阶段&#34;&gt;3. &lt;code&gt;NGX_HTTP_FIND_CONFIG_PHASE&lt;/code&gt; (配置查找阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 根据上个阶段处理完的 URI，查找并匹配对应的 &lt;code&gt;location&lt;/code&gt; 配置块。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;核心功能&lt;/strong&gt;: 这是 Nginx 路由的核心。Nginx 会用请求的 URI 与 &lt;code&gt;location&lt;/code&gt; 指令定义的规则进行匹配，找到最合适的 &lt;code&gt;location&lt;/code&gt;。这个阶段没有模块可以注册 handler，是 Nginx 核心自己完成的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;4ngx_http_rewrite_phaselocation-级别地址重写阶段&#34;&gt;4. &lt;code&gt;NGX_HTTP_REWRITE_PHASE&lt;/code&gt; (Location 级别地址重写阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 在上一步匹配到的 &lt;code&gt;location&lt;/code&gt; 块内部，执行 URL 重写。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;rewrite&lt;/code&gt; 指令（当它定义在 &lt;code&gt;location&lt;/code&gt; 块中时）、&lt;code&gt;set&lt;/code&gt; 指令。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 对特定 &lt;code&gt;location&lt;/code&gt; 的请求进行更精细的 URL 改写。这个阶段的 &lt;code&gt;rewrite&lt;/code&gt; 可能会导致 Nginx 重新回到 &lt;code&gt;FIND_CONFIG&lt;/code&gt; 阶段去匹配新的 &lt;code&gt;location&lt;/code&gt;，可能会有循环，最多执行 10 次以防止死循环。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/app/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 这个 rewrite 工作在 REWRITE 阶段&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;rewrite&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;^/app/(.*)&lt;/span&gt;$ &lt;span class=&#34;s&#34;&gt;/v2/app/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;5ngx_http_post_rewrite_phase地址重写后阶段&#34;&gt;5. &lt;code&gt;NGX_HTTP_POST_REWRITE_PHASE&lt;/code&gt; (地址重写后阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 防止 &lt;code&gt;rewrite&lt;/code&gt; 阶段的重写指令导致死循环。如果 URI 在上一个阶段被重写，这个阶段会把重写后的 URI 交给 Nginx，让其重新开始 &lt;code&gt;FIND_CONFIG&lt;/code&gt; 阶段，查找新的 &lt;code&gt;location&lt;/code&gt;。这是一个内部阶段，用户通常不直接感知。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;6ngx_http_preaccess_phase访问权限控制前置阶段&#34;&gt;6. &lt;code&gt;NGX_HTTP_PREACCESS_PHASE&lt;/code&gt; (访问权限控制前置阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 在正式的访问权限检查之前，做一些准备工作。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块&lt;/strong&gt;: &lt;code&gt;ngx_http_limit_conn_module&lt;/code&gt; (连接数限制), &lt;code&gt;ngx_http_limit_req_module&lt;/code&gt; (请求速率限制)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 在检查用户名密码之前，先检查客户端的请求速率是否过快，如果过快，直接拒绝，不必再执行后面的阶段。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;7ngx_http_access_phase访问权限控制阶段&#34;&gt;7. &lt;code&gt;NGX_HTTP_ACCESS_PHASE&lt;/code&gt; (访问权限控制阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 对请求进行权限验证。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;ngx_http_access_module&lt;/code&gt; (&lt;code&gt;allow&lt;/code&gt;, &lt;code&gt;deny&lt;/code&gt;), &lt;code&gt;ngx_http_auth_basic_module&lt;/code&gt; (HTTP 基本认证)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 检查客户端 IP 是否在允许列表中，或者验证用户提供的用户名和密码是否正确。如果这个阶段有任何模块拒绝了请求，处理就会立即中断并返回错误（如 403 Forbidden）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;8ngx_http_post_access_phase访问权限控制后置阶段&#34;&gt;8. &lt;code&gt;NGX_HTTP_POST_ACCESS_PHASE&lt;/code&gt; (访问权限控制后置阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 主要用于配合 &lt;code&gt;ACCESS&lt;/code&gt; 阶段的 &lt;code&gt;satisfy&lt;/code&gt; 指令。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 当 &lt;code&gt;satisfy any;&lt;/code&gt; 被使用时，如果 &lt;code&gt;ACCESS&lt;/code&gt; 阶段有模块允许了访问（例如 IP 匹配成功），&lt;code&gt;POST_ACCESS&lt;/code&gt; 阶段的处理就可以被跳过。如果 &lt;code&gt;ACCESS&lt;/code&gt; 阶段没有明确允许，这个阶段的处理（例如 HTTP 基本认证）就会被执行。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;9ngx_http_try_files_phasetry_files-阶段&#34;&gt;9. &lt;code&gt;NGX_HTTP_TRY_FILES_PHASE&lt;/code&gt; (Try_files 阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: &lt;code&gt;try_files&lt;/code&gt; 指令专属的特殊阶段。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;try_files&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 按顺序检查文件或目录是否存在，如果找到，则内部重定向到该文件，如果都找不到，则执行最后一个参数（通常是内部重定向到一个 &lt;code&gt;location&lt;/code&gt; 或返回一个状态码）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 这个指令工作在 TRY_FILES 阶段&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;try_files&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$uri/&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/index.html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;10ngx_http_content_phase内容生成阶段&#34;&gt;10. &lt;code&gt;NGX_HTTP_CONTENT_PHASE&lt;/code&gt; (内容生成阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: &lt;strong&gt;核心阶段&lt;/strong&gt;，负责生成最终的响应内容并发送给客户端。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;重要特性&lt;/strong&gt;: 每个 &lt;code&gt;location&lt;/code&gt; 只有一个模块能成为“内容处理模块”（Content Handler）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块&lt;/strong&gt;:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;ngx_http_static_module&lt;/code&gt;: 处理静态文件。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ngx_http_proxy_module&lt;/code&gt;: 将请求反向代理到后端服务器 (&lt;code&gt;proxy_pass&lt;/code&gt;)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ngx_http_fastcgi_module&lt;/code&gt;: 将请求转发给 FastCGI 应用（如 PHP-FPM）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ngx_http_index_module&lt;/code&gt;: 处理目录索引文件。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;return&lt;/code&gt;: 直接返回指定的状态码或内容。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;执行逻辑&lt;/strong&gt;: Nginx 会调用在 &lt;code&gt;location&lt;/code&gt; 中找到的内容处理模块。例如，如果配置了 &lt;code&gt;proxy_pass&lt;/code&gt;，那么 &lt;code&gt;proxy_module&lt;/code&gt; 就会接管请求。如果没有特定的内容处理模块，默认会由 &lt;code&gt;static_module&lt;/code&gt; 尝试提供静态文件服务。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;11ngx_http_log_phase日志记录阶段&#34;&gt;11. &lt;code&gt;NGX_HTTP_LOG_PHASE&lt;/code&gt; (日志记录阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 请求处理完成后，记录访问日志。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;ngx_http_log_module&lt;/code&gt; (&lt;code&gt;access_log&lt;/code&gt;)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举-例&lt;/strong&gt;: 无论请求成功还是失败，这个阶段都会被执行（除非有严重错误），用于将请求的相关信息（如客户端IP、请求时间、状态码等）写入到日志文件中。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;过滤器模块-filter-modules&#34;&gt;过滤器模块 (Filter Modules)&lt;/h4&gt;&#xA;&lt;p&gt;当 &lt;code&gt;CONTENT&lt;/code&gt; 阶段生成了响应内容后，在发送给客户端之前，响应数据还会经过一系列的 &lt;strong&gt;过滤器（Filter）&lt;/strong&gt; 链处理。过滤器负责对响应头和响应体进行修改或加工。&lt;/p&gt;</description>
			</item>
			<item>
				<title>WebSocket Origin Header 校验失败</title>
				<link>https://blog.jinzhi.site/posts/2025-10/websocket-origin-header-%E6%A0%A1%E9%AA%8C%E5%A4%B1%E8%B4%A5/</link>
				<pubDate>Tue, 21 Oct 2025 15:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-10/websocket-origin-header-%E6%A0%A1%E9%AA%8C%E5%A4%B1%E8%B4%A5/</guid>
				<description>&lt;p&gt;最近做 APISIX 线上服务时遇到一个场景：业务使用 websocket 转发时，在浏览器会出现 WebSocket close with status code 1006 的错误。打开调试工具查看发现在 websocket 握手时服务端返回了 403。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/websocket-origin-header-%E6%A0%A1%E9%AA%8C%E5%A4%B1%E8%B4%A5/76f75e967736245ec923202987a22482_MD5.jpeg&#34; alt=&#34;76f75e967736245ec923202987a22482_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/websocket-origin-header-%E6%A0%A1%E9%AA%8C%E5%A4%B1%E8%B4%A5/4efbf4b7a2093ed4f1d6e522139dc92e_MD5.jpeg&#34; alt=&#34;4efbf4b7a2093ed4f1d6e522139dc92e_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;非常奇怪的是，如果业务不经过 APISIX 直接访问后端 code-server 是没有问题的（中间也得经过一层 Ingress 转发）。&lt;/p&gt;&#xA;&lt;p&gt;简单的流量模型如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;                                                                                                                      &#xA;                                                                                                                      &#xA;                               +--------------+                              +--------------+          +-------------+&#xA;  https://domain.com:9443/xxx  |              |  http://domain.com:23480/xxx |              |          |             |&#xA;--------------------------------   APISIX     -------------------------------+   Ingress    -----------+ code-server |&#xA;                               |              |                              |              |          |             |&#xA;                               +--------------+                              +--------------+          +-------------+&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;经过对比发现，两者的请求头里面 Host 和 Origin 是存在差异的。尝试在 APISIX 中强制修改 Host 头部，问题没有解决。然后利用 proxy-rewrite 强制修改 Origin 头部，请求恢复正常。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;plugins&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;proxy-rewrite&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uri&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/anything&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;headers&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;#34;set&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;Origin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http://domain.com&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么问题来了，为什么改完 Origin Header 就行了？code-server 是如何处理 Origin Header 的？为什么 Ingress 可以，APISIX 不行？&lt;/p&gt;</description>
			</item>
			<item>
				<title>Introducing Kubernetes Gateway API</title>
				<link>https://blog.jinzhi.site/posts/2025-10/introducing-kubernetes-gateway-api/</link>
				<pubDate>Thu, 16 Oct 2025 16:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-10/introducing-kubernetes-gateway-api/</guid>
				<description>&lt;p&gt;Kubernetes Gateway API 是一个由 SIG-Network 孵化和维护的 &lt;strong&gt;开放、标准、可扩展的 API&lt;/strong&gt;，旨在为 Kubernetes 集群内部和外部的统一流量管理提供更强大、更灵活、更具表现力的方式。&lt;/p&gt;&#xA;&lt;p&gt;它被视为 &lt;strong&gt;Ingress API 的继任者和演进&lt;/strong&gt;，解决了 Ingress 在灵活性、可扩展性、角色分离和 L4-L7 支持方面的诸多局限性。Gateway API 不仅仅关注 HTTP 流量，还支持 TCP、UDP 以及 TLS 路由，覆盖了更广泛的网络场景。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么需要-gateway-api&#34;&gt;为什么需要 Gateway API&lt;/h2&gt;&#xA;&lt;p&gt;在 Gateway API 出现之前，Kubernetes 主要使用 &lt;code&gt;Ingress&lt;/code&gt; 来管理集群的 L7 HTTP/HTTPS 流量。然而，Ingress 存在一些固有的局限性，促使了 Gateway API 的诞生：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;功能有限：&lt;/strong&gt; Ingress 本身功能非常基础，只支持主机和路径路由。任何高级功能（如流量拆分、重写、限速、认证等）都必须通过特定于 Ingress 控制器（如 NGINX Ingress, Traefik, AWS ALB Ingress 等）的 &lt;strong&gt;注解（Annotations）&lt;/strong&gt; 来实现。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;可移植性差：&lt;/strong&gt; 注解是特定于实现的，这意味着用 NGINX Ingress 注解编写的规则无法直接移植到 Traefik 或其他 Ingress 控制器上，造成供应商锁定。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;缺乏角色分离：&lt;/strong&gt; Ingress 资源将网络基础设施的配置（例如暴露的端口、TLS 证书）与应用程序的路由规则混在一起，这使得集群管理员和应用开发者之间的职责难以清晰划分。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;L4 流量支持不足：&lt;/strong&gt; Ingress 仅专注于 HTTP/HTTPS (L7) 流量。对于 TCP、UDP 或 TLS 直通（Passthrough）等 L4 流量，通常需要使用 &lt;code&gt;LoadBalancer&lt;/code&gt; 类型的 Service 或其他的解决方案。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;表达能力有限：&lt;/strong&gt; 难以表达复杂的路由策略，如基于请求头、查询参数的匹配，细粒度的流量权重分配等。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Gateway API 旨在解决这些问题，提供一个更加健壮和通用的流量管理框架。&lt;/p&gt;</description>
			</item>
			<item>
				<title>APISIX balancer 支持 domain</title>
				<link>https://blog.jinzhi.site/posts/2025-10/apisix-balancer-%E6%94%AF%E6%8C%81-domain/</link>
				<pubDate>Sun, 12 Oct 2025 15:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-10/apisix-balancer-%E6%94%AF%E6%8C%81-domain/</guid>
				<description>&lt;p&gt;最近在做网关开发时遇到了一个场景：&lt;strong&gt;业务在做多实例部署时需要通过 Ingress 将服务注册给 APISIX，由于每个实例属于一个单独的 namespace，导致在 APISIX 和 Ingress 上出现流量覆盖的问题：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Ingress 通过 Host 和 URI 匹配入向流量，同一个服务的 Host 和 URI 是完全一致的（Host 用 ip:port 表示），因此注册多个 Ingress 流量只会引流到一个实例上。&lt;/li&gt;&#xA;&lt;li&gt;APISIX 侧在 balance 阶段对于相同 ip:port 的 upstream node 会做去重，导致跨集群多实例时流量分配并不符合预期。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;举个例子，有 A，B 两个集群，A 集群部署了 2 个实例，B 集群部署了一个实例。预期这 3 个实例应该平均分配流量（假设采用 rr），A 集群和 B 集群流量比例应该是 2:1，但实际上 A 集群和 B 集群在 APISIX 分配时流量是 1:1，而在 A 集群内一个实例占据了全部流量。&lt;/p&gt;&#xA;&lt;p&gt;从业务上来说这个可以通过重新规划 namespace 和实例的关系来解决。同一个集群同一个服务的所有实例分布在同一个 namespace 中。这样注册的 Ingress 和 APISIX upstream node 就只会有一个。&lt;/p&gt;&#xA;&lt;p&gt;抛开这个点，我们来看看从网关的角度如何解决这两个问题。&lt;/p&gt;&#xA;&lt;p&gt;第一个问题比较好解决，每个注册的实例采用独立的 Domain，Ingress 通过 Host Header 来区分流量。在 APISIX 采用域名注册，域名解析到 Ingress 地址。如果域名没法解析（我们遇到的场景），也可以将 Domain 信息放到 node 的 metadata 内，写一个插件将其注入到 node.domain 内来完成。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
