📎 配套脚本附件正文未内嵌 · 共 9 个 · 点开可在线查看
📚 另需公共库(正文未重复内嵌,点名字直接看):_bootstrap.py
📂 查看全部 761 个脚本附件 →
⚠️ 脚本内含明文凭据(与本页正文一致),请勿在公网环境直接运行。
集成环境 · Higress

Higress 之三 · 总入口路由与验收

/llm /xf 与 dify.ai.local Host 路由、curl 验收。

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/* → LiteLLMAuthorization: Bearer …sk-litellm-bocheng-207
/xf/* → XinferenceAuthorization: Bearer …xf-K8H3LiS27H4188XdOyWJj74MWMOlIR9tZbiybDbxbSas7eAI
Dify 浏览器登录(经 dify.ai.local)邮箱 / 密码38205036@qq.com / Difyai123456
OpenAI SDK api_key(base=…/llm/v1)同 LiteLLMsk-litellm-bocheng-207
上游 vLLM(仅 LiteLLM 配置里,客户端通常不带)Bearer123456

不要混用: /llm 用 sk-litellm-…;/xf 用 xf-…。串了会 401。

系列总表见之一 §0。


1. 目标路由(落地后)

名称匹配后端服务Rewrite
llm / llm-root前缀 /llm/、/llmlitellm.static:4000去前缀 → /
xf / xf-root前缀 /xf/、/xfxinference.static:9997去前缀 → /
dify-hostHost=dify.ai.local,路径 /dify.static:80关闭

服务源(static):

namedomain
litellm192.168.110.207:4000
xinference192.168.110.207:9997
dify192.168.110.207:80

2. 一键配置(推荐)

bash
# 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)

text
192.168.110.207  dify.ai.local

浏览器:http://dify.ai.local:18080/


4. 验收 curl

bash
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 / 307

Python(经 Higress → LiteLLM)

python
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 去前缀后:

bash
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

同时:

bash
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 前端跳转策略,不是「整站挂了」。

逐步处理

  1. Console 登录后列出路由,确认存在 dify / dify-root。
  2. 删除它们:
bash
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
  1. 创建域名与 Host 路由:
bash
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}
  }'
  1. 验收(未登录 307 可接受):
bash
curl -sS -o /dev/null -w "%{http_code}\n" \
  -H "Host: dify.ai.local" http://127.0.0.1:18080/
# 307 或 200
  1. 本机 hosts 增加 192.168.110.207 dify.ai.local 后用浏览器打开。

Higress_02_配置路由.sh 已按上述逻辑固化(见附录)。


案例 B:服务源填 127.0.0.1 → 网关 502 / 无上游

现象

路由已创建,但:

bash
curl -sS http://127.0.0.1:18080/llm/v1/models -H "Authorization: Bearer sk-litellm-bocheng-207"
# 空、超时或 502

同时宿主机直连正常:

bash
curl -sS http://127.0.0.1:4000/health/liveliness
# I'm alive!

原因

Higress Gateway 在容器网络内;127.0.0.1 是 gateway 容器 loopback。

排查

bash
# 确认服务源
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 源会暴露为:

text
litellm.static
dify.static
xinference.static

(对照内置 higress-console.dns 的命名规律:<sourceName>.<type>。)

解决

路由 JSON 使用:

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(完整)

bash
#!/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(完整)

bash
#!/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 总入口验收通过"