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

Express.js服务器Postman请求正常,浏览器访问出现404及连接拒绝错误

问题:浏览器请求Express服务后服务器崩溃,Postman正常运行

我的Express.js服务器代码

const express = require("express");
const app = express();
const axios = require("axios");
const PORT = 3000;
var cors = require("cors");
app.use(cors());
app.use(express.json());
require("dotenv").config();
const token = process.env.GitHub_Token;

// routes
app.get("/:name", (req, res) => {
  getRepositoryNames(req.params.name).then((repositories) => {
    getRepositoryLanguages(req.params.name, repositories).then(
      (languageStats) => {
        res.send(languageStats);
      }
    );
  });
});

function getRepositoryNames(username) {
  return axios
    .get(`https://api.github.com/users/${username}/repos`, {
      headers: {
        Authorization: `token ${token}`,
      },
    })
    .then((response) => {
      return response.data
        .map((repo) => ({
          name: repo.name,
        }))
        .map((e) => e.name);
    })
    .catch((error) => {
      console.log(error);
      return Promise.reject(error);
    });
}

async function getRepositoryLanguages(owner, repos) {
  let languageStats = [];

  for (let index = 0; index < repos.length; index++) {
    const repoName = repos[index];

    const response = await axios.get(
      `https://api.github.com/repos/${owner}/${repoName}/languages`,
      {
        headers: {
          Authorization: `token ${token}`,
        },
      }
    );

    languageStats.push({
      repoName: repoName,
      languages: response.data,
    });
  }
  const res = languageStats.reduce(
    (a, b) => {
      a.repositories.push(b.repoName);
      for (const lang of Object.keys(b.languages)) {
        if (a.languages.hasOwnProperty(lang)) {
          a.languages[lang] += b.languages[lang];
        } else {
          a.languages[lang] = b.languages[lang];
        }
      }
      return a;
    },
    { languages: {}, repositories: [] }
  );

  const totBytes = Object.values(res.languages).reduce((a, b) => a + b);

  for (const lang of Object.keys(res.languages)) {
    res.languages[lang] = res.languages[lang] / totBytes;
  }

  return res;
}
app.listen(PORT, () => {
  console.log(`API server listening at http://localhost:${PORT}`);
});

问题详情

这段代码仅作演示用,打算部署到Kubernetes,不需要前端,直接用浏览器发GET请求就行。现在用Postman访问localhost:3000/user完全正常,但用Chrome或其他浏览器请求时,虽然能拿到数据,但服务器立刻崩溃,之后会出现404错误和ERR_CONNECTION_REFUSED提示。我怀疑浏览器请求里缺了Postman带的某些请求头,但不知道具体是哪些,也不清楚要给Axios的GET请求加什么头。


排查与修复方案

1. 先补全错误处理,定位崩溃根源

当前代码的Promise链没有全局错误捕获,一旦getRepositoryLanguages调用GitHub API出错,会触发未捕获的Promise拒绝,直接导致服务器崩溃。

修改路由逻辑,改用async/await并添加try/catch:

app.get("/:name", async (req, res) => {
  try {
    const repositories = await getRepositoryNames(req.params.name);
    const languageStats = await getRepositoryLanguages(req.params.name, repositories);
    res.send(languageStats);
  } catch (error) {
    console.error("请求处理失败:", error);
    // 根据GitHub API的响应返回对应状态码,比如用户不存在返回404
    res.status(error.response?.status || 500).send({ error: error.message });
  }
});

同时给getRepositoryLanguages添加单仓库请求的错误捕获,避免单个仓库出错导致整个流程中断:

async function getRepositoryLanguages(owner, repos) {
  let languageStats = [];

  for (let index = 0; index < repos.length; index++) {
    const repoName = repos[index];
    try {
      const response = await axios.get(
        `https://api.github.com/repos/${owner}/${repoName}/languages`,
        {
          headers: {
            Authorization: `token ${token}`,
          },
        }
      );

      languageStats.push({
        repoName: repoName,
        languages: response.data,
      });
    } catch (error) {
      console.error(`获取仓库${repoName}语言信息失败:`, error);
      // 跳过出错的仓库,继续处理其他仓库
      continue;
    }
  }
  // 后续统计逻辑不变
}

2. 统一Axios请求头,匹配浏览器行为

浏览器发起请求时会自动携带User-Agent、Accept等头,Postman默认的头更贴近标准请求,给Axios添加这些头可以避免GitHub API返回非预期响应:

// 定义通用请求头
const commonHeaders = {
  Authorization: `token ${token}`,
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
  Accept: "application/json"
};

// 在getRepositoryNames中使用
axios.get(`https://api.github.com/users/${username}/repos`, { headers: commonHeaders })

// 在getRepositoryLanguages的请求中同样替换headers为commonHeaders

3. 处理浏览器自动发起的额外请求

浏览器访问接口时,会自动请求/favicon.ico,当前代码没有这个路由,会返回404,虽然不会直接导致崩溃,但可以添加默认路由统一处理:

app.get("*", (req, res) => {
  res.status(404).send("接口不存在");
});

4. Kubernetes部署注意事项

  • 确保Pod通过Secret正确挂载GitHub_Token环境变量
  • 服务的端口映射要指向容器的3000端口(NodePort/Ingress配置正确)
  • 用kubectl logs <pod-name>查看Pod日志,获取服务器崩溃的具体报错信息,比本地调试更准确

内容的提问来源于stack exchange,提问作者user346206

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 12:40:41