Higress 之三 · 总入口路由配置与验收
前置:之二已安装且 Console 可登录(已
/system/init)HTML:
docs/html_cursor/Higress_之三_总入口路由配置与验收_cursor.html本文含:路由步骤、本次路由/验收实战排错、完整配置与验收脚本附录
0. 本册涉及凭据(路由 / 验收 / API)
| 用途 | Header 或登录 | 完整值 |
|---|---|---|
| Higress Console(配路由脚本登录) | 用户名 / 密码 | admin / Higress207admin! |
| Console URL | — | http://192.168.110.207:8001 或本机 http://127.0.0.1:8001 |
/llm/* → LiteLLM | Authorization: Bearer … | sk-litellm-bocheng-207 |
/xf/* → Xinference | Authorization: Bearer … | xf-K8H3LiS27H4188XdOyWJj74MWMOlIR9tZbiybDbxbSas7eAI |
Dify 浏览器登录(经 dify.ai.local) | 邮箱 / 密码 | 38205036@qq.com / Difyai123456 |
OpenAI SDK api_key(base=…/llm/v1) | 同 LiteLLM | sk-litellm-bocheng-207 |
| 上游 vLLM(仅 LiteLLM 配置里,客户端通常不带) | Bearer | 123456 |
不要混用: /llm 用 sk-litellm-…;/xf 用 xf-…。串了会 401。
系列总表见之一 §0。
1. 目标路由(落地后)
| 名称 | 匹配 | 后端服务 | Rewrite |
|---|---|---|---|
llm / llm-root | 前缀 /llm/、/llm | litellm.static:4000 | 去前缀 → / |
xf / xf-root | 前缀 /xf/、/xf | xinference.static:9997 | 去前缀 → / |
dify-host | Host=dify.ai.local,路径 / | dify.static:80 | 关闭 |
服务源(static):
| name | domain |
|---|---|
| litellm | 192.168.110.207:4000 |
| xinference | 192.168.110.207:9997 |
| dify | 192.168.110.207:80 |
2. 一键配置(推荐)
# 207(先保证已 init + 可 login)
bash /opt/workbuddy/scripts_bash_cursor/Higress部署/Higress_02_配置路由.sh
bash /opt/workbuddy/scripts_bash_cursor/Higress部署/Higress_03_验收.sh也可在 Console UI:服务来源 → 域名管理 → 路由管理,按上表手点。
3. hosts(Dify)
192.168.110.207 dify.ai.local浏览器:http://dify.ai.local:18080/
4. 验收 curl
curl -sS http://192.168.110.207:18080/llm/v1/models \
-H "Authorization: Bearer sk-litellm-bocheng-207"
curl -sS http://192.168.110.207:18080/xf/v1/models \
-H "Authorization: Bearer xf-K8H3LiS27H4188XdOyWJj74MWMOlIR9tZbiybDbxbSas7eAI"
curl -sS -o /dev/null -w "%{http_code}\n" \
-H "Host: dify.ai.local" http://192.168.110.207:18080/
# 期望 200 / 301 / 302 / 307Python(经 Higress → LiteLLM)
from openai import OpenAI
client = OpenAI(
api_key="sk-litellm-bocheng-207",
base_url="http://192.168.110.207:18080/llm/v1",
)
print(client.chat.completions.create(
model="qwen3.6-27b",
messages=[{"role": "user", "content": "你好"}],
max_tokens=64,
).choices[0].message.content)5. 本次实装案例:路由与验收排错
案例 A:/dify/ 返回 307 且 Location 丢掉前缀
现象(2026-08-26 实测)
配置路径路由 /dify/ + rewrite 去前缀后:
curl -sS -o /dev/null -w "%{http_code} redirect=%{redirect_url}\n" \
http://127.0.0.1:18080/dify/
# 307 redirect=http://127.0.0.1:18080/auth/refresh?redirect_url=%2F同时:
curl -sS http://127.0.0.1:18080/llm/v1/models -H "Authorization: Bearer sk-litellm-bocheng-207" | head -c 200
# 正常 JSON,含 qwen / bge-m3 …说明:网关与 LiteLLM 链路正常,问题在 Dify 前端跳转策略,不是「整站挂了」。
逐步处理
- Console 登录后列出路由,确认存在
dify/dify-root。 - 删除它们:
COOKIE=/tmp/hc.ck
# 先 login 拿到 cookie(略)
curl -sS -b $COOKIE -X DELETE http://127.0.0.1:8001/v1/routes/dify
curl -sS -b $COOKIE -X DELETE http://127.0.0.1:8001/v1/routes/dify-root- 创建域名与 Host 路由:
curl -sS -b $COOKIE -X POST http://127.0.0.1:8001/v1/domains \
-H "Content-Type: application/json" \
-d '{"name":"dify.ai.local","enableHttps":"off"}'
curl -sS -b $COOKIE -X POST http://127.0.0.1:8001/v1/routes \
-H "Content-Type: application/json" \
-d '{
"name":"dify-host",
"domains":["dify.ai.local"],
"path":{"matchType":"PRE","matchValue":"/","caseSensitive":false},
"services":[{"name":"dify.static","port":80,"weight":100}],
"rewrite":{"enabled":false},
"authConfig":{"enabled":false}
}'- 验收(未登录 307 可接受):
curl -sS -o /dev/null -w "%{http_code}\n" \
-H "Host: dify.ai.local" http://127.0.0.1:18080/
# 307 或 200- 本机 hosts 增加
192.168.110.207 dify.ai.local后用浏览器打开。
Higress_02_配置路由.sh 已按上述逻辑固化(见附录)。
案例 B:服务源填 127.0.0.1 → 网关 502 / 无上游
现象
路由已创建,但:
curl -sS http://127.0.0.1:18080/llm/v1/models -H "Authorization: Bearer sk-litellm-bocheng-207"
# 空、超时或 502同时宿主机直连正常:
curl -sS http://127.0.0.1:4000/health/liveliness
# I'm alive!原因
Higress Gateway 在容器网络内;127.0.0.1 是 gateway 容器 loopback。
排查
# 确认服务源
curl -sS -b /tmp/hc.ck http://127.0.0.1:8001/v1/service-sources | python3 -m json.tool | grep -A5 litellm解决
把 static 的 domain 改为 192.168.110.207:4000(及 80/9997),重建或更新服务源后重试。本次脚本默认即该 IP。
案例 C:路由里的服务名必须是 名字.static
现象
创建路由时若 services[].name 写成 litellm 而不是 litellm.static,Console 可能报错或流量无上游。
依据
列服务时,static 源会暴露为:
litellm.static
dify.static
xinference.static(对照内置 higress-console.dns 的命名规律:<sourceName>.<type>。)
解决
路由 JSON 使用:
"services": [{"name": "litellm.static", "port": 4000, "weight": 100}]案例 D:验收脚本判定 Dify「失败」——只认 200
说明
未登录访问 Dify 常返回 307/302。验收脚本须把 301/302/307 与 200 一并视为「网关打到了 Dify」。Higress_03_验收.sh 已按此实现;手工判断时不要只盯 200。
案例 E:Key 混用
| 路径 | 正确 Bearer |
|---|---|
/llm/... | sk-litellm-bocheng-207 |
/xf/... | xf-K8H3LiS27H4188XdOyWJj74MWMOlIR9tZbiybDbxbSas7eAI |
用反会 401,与路由无关。
下一篇:增强与附录 → Higress_之四_增强限流鉴权与补丁附录_cursor.md
附录 A:Higress_02_配置路由.sh(完整)
#!/usr/bin/env bash
# 配置 Higress 三条总入口路由:/llm → LiteLLM,/dify → Dify,/xf → Xinference
set -euo pipefail
CONSOLE="${HIGRESS_CONSOLE:-http://127.0.0.1:8001}"
USER="${HIGRESS_ADMIN_USER:-admin}"
PASS="${HIGRESS_ADMIN_PASS:-Higress207admin!}"
BACKEND_HOST="${HIGRESS_BACKEND_HOST:-192.168.110.207}"
COOKIE="$(mktemp)"
trap 'rm -f "$COOKIE"' EXIT
login() {
curl -sS -c "$COOKIE" -b "$COOKIE" -X POST "$CONSOLE/session/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"$USER\",\"password\":\"$PASS\"}" | tee /tmp/higress_login.json
echo
if ! grep -q '"name"' /tmp/higress_login.json; then
echo "[FAIL] Console 登录失败(若未初始化,先 POST /system/init)"
exit 1
fi
}
put_json() {
local path="$1" body="$2"
curl -sS -b "$COOKIE" -X PUT "$CONSOLE$path" \
-H "Content-Type: application/json" \
-d "$body"
echo
}
post_json() {
local path="$1" body="$2"
curl -sS -b "$COOKIE" -X POST "$CONSOLE$path" \
-H "Content-Type: application/json" \
-d "$body"
echo
}
ensure_source() {
local name="$1" domain="$2" port="$3"
if curl -sS -b "$COOKIE" "$CONSOLE/v1/service-sources" | grep -q "\"name\":\"$name\""; then
echo "[INFO] service-source 已存在: $name"
return 0
fi
echo "[INFO] 创建 service-source: $name → $domain"
post_json /v1/service-sources "$(cat <<EOF
{
"name": "$name",
"type": "static",
"domain": "$domain",
"port": $port,
"protocol": "HTTP",
"authN": {"enabled": false}
}
EOF
)"
}
ensure_route() {
local name="$1" prefix="$2" svc="$3" port="$4"
local body
body="$(cat <<EOF
{
"name": "$name",
"domains": [],
"path": {
"matchType": "PRE",
"matchValue": "$prefix",
"caseSensitive": false
},
"services": [
{"name": "$svc", "port": $port, "weight": 100}
],
"rewrite": {
"enabled": true,
"path": "/"
},
"authConfig": {"enabled": false}
}
EOF
)"
if curl -sS -b "$COOKIE" "$CONSOLE/v1/routes" | grep -q "\"name\":\"$name\""; then
echo "[INFO] 更新路由: $name"
put_json "/v1/routes/$name" "$body"
else
echo "[INFO] 创建路由: $name ($prefix → $svc)"
post_json /v1/routes "$body"
fi
}
echo "[INFO] Console=$CONSOLE backend=$BACKEND_HOST"
login
ensure_source "litellm" "${BACKEND_HOST}:4000" 4000
ensure_source "dify" "${BACKEND_HOST}:80" 80
ensure_source "xinference" "${BACKEND_HOST}:9997" 9997
ensure_route "llm" "/llm/" "litellm.static" 4000
ensure_route "xf" "/xf/" "xinference.static" 9997
ensure_route "llm-root" "/llm" "litellm.static" 4000
ensure_route "xf-root" "/xf" "xinference.static" 9997
DIFY_HOST="${DIFY_HOST:-dify.ai.local}"
if curl -sS -b "$COOKIE" "$CONSOLE/v1/domains" | grep -q "\"name\":\"$DIFY_HOST\""; then
echo "[INFO] 域名已存在: $DIFY_HOST"
else
echo "[INFO] 创建域名: $DIFY_HOST"
post_json /v1/domains "{\"name\":\"$DIFY_HOST\",\"enableHttps\":\"off\"}"
fi
DIFY_BODY="$(cat <<EOF
{
"name": "dify-host",
"domains": ["$DIFY_HOST"],
"path": {"matchType": "PRE", "matchValue": "/", "caseSensitive": false},
"services": [{"name": "dify.static", "port": 80, "weight": 100}],
"rewrite": {"enabled": false},
"authConfig": {"enabled": false}
}
EOF
)"
if curl -sS -b "$COOKIE" "$CONSOLE/v1/routes" | grep -q '"name":"dify-host"'; then
put_json /v1/routes/dify-host "$DIFY_BODY"
else
post_json /v1/routes "$DIFY_BODY"
fi
curl -sS -b "$COOKIE" -X DELETE "$CONSOLE/v1/routes/dify" >/dev/null 2>&1 || true
curl -sS -b "$COOKIE" -X DELETE "$CONSOLE/v1/routes/dify-root" >/dev/null 2>&1 || true
echo "[INFO] 请在客户端 hosts 增加: ${BACKEND_HOST} ${DIFY_HOST}"
echo "[OK] 路由配置完成"附录 B:Higress_03_验收.sh(完整)
#!/usr/bin/env bash
# 验收 Higress 总入口(llm / xf / dify-host)
set -euo pipefail
GW="${HIGRESS_BASE:-http://127.0.0.1:18080}"
LITELLM_KEY="${LITELLM_MASTER_KEY:-sk-litellm-bocheng-207}"
XF_KEY="${XF_KEY:-xf-K8H3LiS27H4188XdOyWJj74MWMOlIR9tZbiybDbxbSas7eAI}"
DIFY_HOST="${DIFY_HOST:-dify.ai.local}"
fail=0
echo "[1] /llm/v1/models"
if curl -sf -m 20 "$GW/llm/v1/models" -H "Authorization: Bearer $LITELLM_KEY" | grep -q qwen; then
echo " OK"
else
echo " FAIL"; fail=1
fi
echo "[2] /xf/v1/models"
if curl -sf -m 20 "$GW/xf/v1/models" -H "Authorization: Bearer $XF_KEY" | grep -q bge; then
echo " OK"
else
echo " FAIL"; fail=1
fi
echo "[3] Host $DIFY_HOST → Dify"
code=$(curl -sS -m 20 -o /dev/null -w "%{http_code}" -H "Host: $DIFY_HOST" "$GW/")
if [ "$code" = "200" ] || [ "$code" = "302" ] || [ "$code" = "307" ] || [ "$code" = "301" ]; then
echo " OK http=$code"
else
echo " FAIL http=$code"; fail=1
fi
echo "[4] 直连仍可用(对照)"
curl -sf -m 10 http://127.0.0.1:4000/health/liveliness >/dev/null && echo " LiteLLM OK" || { echo " LiteLLM FAIL"; fail=1; }
if [ "$fail" -ne 0 ]; then
echo "[FAIL] 验收未全部通过"
exit 1
fi
echo "[PASS] Higress 总入口验收通过"