You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express+TypeScript中Swagger UI访问短URL路由出现NetworkError

错误:TypeError: 尝试获取资源时发生网络错误

访问路由http://localhost:4001/api/4a7ed517时,该路由在浏览器地址栏、Insomnia等HTTP客户端中均可正常跳转,但在Swagger UI中调用会触发上述网络错误,其余所有路由均正常工作。

Swagger UI路由列表
错误截图

调用生成的短URL时出现该问题,寻求解决方法。

相关代码

Mongoose Schema定义

const urlSchema = new Schema<IUrl>(
  {
    shortID: {
      type: String,
      required: true,
      unique: true,
    },
    redirectURL: {
      type: String,
      required: true,
    },
    visitHistory: [{ timestamp: { type: Number } }],
  },
  { timestamps: true }
);

OpenAPI 3.0配置

{
  "openapi": "3.0.0",
  "info": {
    "title": "URL Shortener API",
    "description": "API for shortening URLs and retrieving analytics",
    "version": "1.0.0",
    "license": {
      "name": "MIT",
      "url": "https://opensource.org/licenses/MIT"
    }
  },
  "paths": {
    "/api/generate": {
      "post": {
        "summary": "Generate Short URL",
        "description": "Generates a new short URL for the provided long URL.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "The original long URL to be shortened."
                  }
                },
                "required": ["url"]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Short URL generated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "description": "The generated short URL."
                    }
                  }
                }
              }
            }
          }
        },
        "tags": [
          "Short URL"
        ]
      }
    },
    "/api/{shortID}": {
      "get": {
        "summary": "Redirect to the original URL using the short ID",
        "parameters": [
          {
            "in": "path",
            "name": "shortID",
            "required": true,
            "description": "The short ID associated with the URL",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to the original URL"
          },
          "404": {
            "description": "Short ID not found"
          }
        },
        "tags": [
          "Redirect"
        ]
      }
    },
    "/api/analytics/{shortID}": {
      "get": {
        "summary": "Get Analytics for Short URL",
        "description": "Retrieves analytics data for a specific short URL, including visit history.",
        "parameters": [
          {
            "name": "shortID",
            "in": "path",
            "required": true,
            "description": "Short identifier for the URL.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successfully retrieved analytics data.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "redirectURL": {
                      "type": "string",
                      "description": "The short URL."
                    },
                    "url": {
                      "type": "string",
                      "description": "The original long URL."
                    },
                    "visitHistory": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "timestamp": {
                            "type": "integer",
                            "description": "Visit timestamp."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "URL not found."
          }
        },
        "tags": [
          "Analytics"
        ]
      }
    }
  }
}

问题原因

Swagger UI依赖浏览器的Fetch API发送请求,而Fetch API默认不会自动跨域跟随302重定向。当短URL重定向到外部第三方网站时,浏览器的CORS策略会阻止Swagger UI完成请求,从而触发NetworkError。而浏览器地址栏或Insomnia这类工具是直接发起导航请求,不受Fetch API的跨域限制,因此可以正常跳转。

解决办法

方案1:修改OpenAPI文档提示用户

在/api/{shortID}接口的summary或description中明确说明:该接口用于浏览器地址栏跳转,Swagger UI中调用仅用于验证存在性,如需跳转请复制完整URL到地址栏访问。

方案2:后端适配Swagger UI请求

检测请求的User-Agent是否包含Swagger关键字,若为Swagger UI的请求,则返回JSON格式的原URL而非302重定向。示例代码(Express为例):

app.get('/api/:shortID', async (req, res) => {
  const { shortID } = req.params;
  const urlDoc = await URLModel.findOne({ shortID });
  if (!urlDoc) return res.status(404).json({ error: 'Short ID not found' });

  // 记录访问历史
  await URLModel.findOneAndUpdate(
    { shortID },
    { $push: { visitHistory: { timestamp: Date.now() } } }
  );

  // 判断是否来自Swagger UI
  const isSwagger = req.get('User-Agent')?.includes('Swagger');
  if (isSwagger) {
    return res.json({ originalUrl: urlDoc.redirectURL });
  }

  // 正常重定向
  res.redirect(urlDoc.redirectURL);
});

方案3:调整Swagger UI配置(有限适用)

如果重定向目标是同域名下的地址,可以在Swagger UI的初始化配置中开启fetch的redirect: 'follow'选项,但此方法对跨域外部URL无效,因为浏览器CORS策略会拦截响应。

内容的提问来源于stack exchange,提问作者Harsh Vardhan Pandey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 17:09:51