Cloud9: 找不到可用的端口。

3

我对NodeJS不熟悉,试图在Cloud9 IDE中设置一个已存在的项目(由他人开发),我使用一个旧的Cloud9帐户(因此不在AWS上运行)。我拉取了git并安装了所有内容,这似乎都没有问题。

要在Cloud9之外本地运行该应用程序,您需要使用npm run start命令启动服务器(我知道来自开发该应用程序的人,这对他有效)。但是我想在Cloud9中设置它,在Cloud9中首先必须设置一些变量(如果我不首先定义主机,则会出现“无效的主机标题”错误),因此我使用以下两个命令:

export HOST=$C9_HOSTNAME && export PORT=8080
npm run start

npm run start 命令会出现以下错误:

无法在 appname-username.c9users.io 上找到空闲端口。

网络错误信息:listen EADDRNOTAVAIL 35.189.252.103

根据 https://docs.c9.io/docs/run-an-application 的说明,我相信端口已经设置正确。我还尝试了 8081、8082 和 $PORT 等值,但都没有生效。

有什么办法可以解决 Cloud9 本地预览的问题吗?


以下是 start.js 的部分代码:

const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';
console.log(`1. The host is ${HOST} on port ${DEFAULT_PORT}`);  //ADDED

choosePort(HOST, DEFAULT_PORT)
  .then(port => {
    console.log(`2. The host is ${HOST} on port ${DEFAULT_PORT}`);  //ADDED
    if (port == null) {
      // We have not found a port.
      return;
    }
    const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
    const appName = require(paths.appPackageJson).name;
    const urls = prepareUrls(protocol, HOST, port);
    // Create a webpack compiler that is configured with custom messages.
    const compiler = createCompiler(webpack, config, appName, urls, useYarn);
    // Load proxy config
    const proxySetting = require(paths.appPackageJson).proxy;
    const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
    // Serve webpack assets generated by the compiler over a web sever.
    const serverConfig = createDevServerConfig(
      proxyConfig,
      urls.lanUrlForConfig
    );
    const devServer = new WebpackDevServer(compiler, serverConfig);
    // Launch WebpackDevServer.
    devServer.listen(port, HOST, err => {
      if (err) {
        return console.log(err);
      }
      if (isInteractive) {
        clearConsole();
      }
      console.log(chalk.cyan('Starting the development server...\n'));
      openBrowser(urls.localUrlForBrowser);
    });

  })
  .catch(err => {
    if (err && err.message) {
      console.log(err.message);
    }
    process.exit(1);
  });

netstat --listen命令会返回以下信息:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN     
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ACC ]     STREAM     LISTENING     1533837857 /home/ubuntu/.c9/6614254/collab.sock
unix  2      [ ACC ]     STREAM     LISTENING     1533835235 /home/ubuntu/.c9/bridge.socket
unix  2      [ ACC ]     STREAM     LISTENING     1533836998 /tmp/tmux-1000/cloud92.2

choosePort函数是node模块"react-dev-utils"的一部分,其内容如下:

function choosePort(host, defaultPort) {
  return detect(defaultPort, host).then(
    port => new Promise(resolve => {
      if (port === defaultPort) {
        return resolve(port);
      }
      if (isInteractive) {
        clearConsole();
        const existingProcess = getProcessForPort(defaultPort);
        const question = {
          type: 'confirm',
          name: 'shouldChangePort',
          message: chalk.yellow(
            `Something is already running on port ${defaultPort}.` +
              `${existingProcess ? ` Probably:\n  ${existingProcess}` : ''}`
          ) + '\n\nWould you like to run the app on another port instead?',
          default: true,
        };
        inquirer.prompt(question).then(answer => {
          if (answer.shouldChangePort) {
            resolve(port);
          } else {
            resolve(null);
          }
        });
      } else {
        console.log(
          chalk.red(`Something is already running on port ${defaultPort}.`)
        );
        resolve(null);
      }
    }),
    err => {
      throw new Error(
        chalk.red(`Could not find an open port at ${chalk.bold(host)}.`) +
          '\n' +
          ('Network error message: ' + err.message || err) +
          '\n'
      );
    }
  );
}

如果您无法找到如何预览正在运行的应用程序,请尝试在URL中使用端口8080。 - RamThakur
我们能够获取node.js代码吗?可能情况是node.js服务器在代码中指定了静态端口,而不是遵循您在启动应用程序之前设置的“PORT”环境变量。 - willascend
@willascend,我已经在帖子中添加了我认为是相关代码的部分。 - Nick
我刚才用nmap扫描了您提供的IP地址,发现8080端口是打开的。您确定您有正确的主机名和应用程序名称吗? - Nick Chapman
谢谢@willascend,我已经将该函数添加到原始帖子中。 - Nick
显示剩余5条评论
1个回答

5
我在搜索了一些资料后发现,你设置的主机值可能有问题。根据这个Cloud9支持帖子提到的类似错误:

...由于c9user.io是代理服务器的公共地址,所以你需要使用0.0.0.0而不是它。或者修改你的/etc/hosts文件。echo "0.0.0.0 $C9_HOSTNAME" | sudo tee -a /etc/hosts

因此,请尝试将主机设置为0.0.0.0而不是公共主机名:

export HOST=0.0.0.0 && export PORT=8080 && npm run start

我在你提供的支持页面上找到了以下内容:
如果您正在开发服务器应用程序,请注意需要监听0.0.0.0($IP)和8080($PORT)。监听此端口将使您的应用程序可在http://-.c9users.io查看。
监听0.0.0.0应该可以解决问题。
编辑(针对返回的其他错误):
对于“无效主机头”错误,我认为您设置disableHostCheck为true是正确的方向,但您的npm脚本命令可能不会遵守CLI中的标志。可能有几种方法可以传递该标志,但最简单的方法可能是在创建开发服务器时更新代码以设置该选项。请记住,这只是一个快速修复,以查看是否可以使其正常工作。最好更新createDevServerConfig函数以设置该选项。
const devServer = new WebpackDevServer(compiler, { ...serverConfig, disableHostCheck: true});

另一个修改:

disableHostCheck选项存在不安全性,并可能会导致漏洞。当在本地测试时,这被认为是一种快速修复方法,并且应仅在封闭网络中使用。要在公开环境中修复“无效主机头”错误,请使用public选项,其中public是您的DNS主机名或公共IP地址:

const devServer = new WebpackDevServer(compiler, { ...serverConfig, public: process.env.PUBLIC_HOST }

您可以通过 CLI 环境将该值传递,就像其他变量一样:
export HOST=0.0.0.0 && export PORT=8080 && export PUBLIC_HOST=$C9_HOSTNAME:8080 && npm run start

免责声明:我认为以上更改不是最好的做法(更新 createDevServerConfig 函数可能更好),但它们应该解决您的问题。有关 disableHostCheck 选项的更多信息可以在此处此处此处找到。

嗨@Nick。我编辑了我的答案。如果我提供的不起作用,你可能需要更新createDevServerConfig函数。此外,根据npm run start脚本实际是什么,可能可以在那里更新并添加CLI选项。 - willascend
如果我更改为 const devServer = new WebpackDevServer(compiler, {serverConfig, disableHostCheck: true});,那么它会出现错误“无效的配置对象。webpack-dev-server已经使用不符合API模式的配置对象进行初始化。-配置具有未知属性'serverConfig'。”我还尝试了 const devServer = new WebpackDevServer(compiler, serverConfig, {disableHostCheck: true});,但似乎它并没有处理disableHostCheck,因为它仍然会出现“无效的主机头”错误。 - Nick
谢谢,太棒了,现在它可以正常工作了!是否还有一种方法可以禁用 HostCheck 而不需要更改代码?(这听起来有点不安全,如果其他人与该代码一起工作不需要禁用它以使其在本地运行,那么他们肯定希望不必禁用它。) - Nick
嗨@Nick,需要进行代码或配置更改才能解决此问题。你能在原始repo上打开一个pull request吗?话虽如此,你关于安全漏洞是正确的。我已经更新了我的答案,也包括public选项,当代理服务器时应该使用它。那样能解决你的问题吗? - willascend
让我们在聊天中继续这个讨论 - willascend
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接