无效的选项对象。使用不符合API架构的选项对象初始化了Dev服务器。

75

在我的package.json中添加"proxy": "http://localhost:6000"后,我在项目中遇到了一个错误。

yarn start之后,出现以下错误响应:

无效的选项对象。Dev Server已使用与API模式不匹配的选项对象进行初始化。

但是当我删除"proxy": "http://localhost:6000"时,一切都正常。

这是我的package.json文件内容:

{
  "name": "client",
  "version": "0.1.0",
  "private": true, 
  "dependencies": {
    "@material-ui/core": "^4.12.3",
    "@testing-library/jest-dom": "^5.16.1",
    "@testing-library/react": "^12.1.2",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^0.24.0",
    "moment": "^2.29.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-file-base64": "^1.0.3",
    "react-redux": "^7.2.6",
    "react-scripts": "5.0.0",
    "redux": "^4.1.2",
    "redux-thunk": "^2.4.1",
    "web-vitals": "^2.1.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "proxy": "http://localhost:6000"
}

1
如果移除后一切正常,为什么不把它移除呢? - Evert
3
因为可能会需要它?我需要它来代理我的 API 请求到我 React 应用程序中的后端。但是,是的,我也在寻找解决方案。 - Adventune
3
这篇文章提供了原因,但尚未提供解决方案。 - Adventune
20个回答

70
这里提供一种解决方法。删除 "proxy": "http://localhost:6000"。使用命令 npm install http-proxy-middleware --save 安装包 http-proxy-middleware。在您的 src 文件夹或根文件夹中创建文件 setupProxy.js。添加以下代码:
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:6000',
      changeOrigin: true,
    })
  );
};

现在运行你的应用程序,它应该可以正常工作。


2
另外,需要指出的是,您可能希望执行以下操作:app.use(createProxyMiddleware('/api', { ...}以便从中间件获得适当的日志记录。 - dmarr
这对我有用。我升级了webpack和node,从我的package.json中删除了代理,然后将现有的API调用升级到路由/api。 - Syllith
1
我的应用仍在3000端口上运行,而不是8000。 - damanpreet singh
1
这可能是一个愚蠢的问题,但当我们创建这个文件并重新运行我们的React应用程序时,当我们进行fetch调用时,代理是如何工作的?它是如何在我们运行开发服务器时自动注册而不需要在任何地方导入它? - Avi Dave
我看到了相同的“无效选项对象…”错误消息,但仅在我尝试离线运行时。当我在线上时一切正常。为什么会这样? - Jason
显示剩余2条评论

33

其他的解决方案对我没有起作用,这是我找到的:

这似乎是一个CRA bug(安全特性?),其中allowedHosts被设置为[undefined],因为当指定主机和代理时,prepareUrls没有设置lanUrlForConfig。相关的CRA GitHub问题在这里

如果在您的使用情况下适当(阅读这里了解更多信息),可以通过创建一个.env文件并添加DANGEROUSLY_DISABLE_HOST_CHECK=true或尝试DANGEROUSLY_DISABLE_HOST_CHECK=true yarn start来避免此问题。


2
DANGEROUSLY_DISABLE_HOST_CHECK是什么?它是一个可行的解决方案吗?"dangerously"部分让我感到怀疑。 - papillon
2
我只在本地开发时使用代理选项,所以我认为这个选项对我来说是安全的! - Emanuele Paolini
1
解决了!谢谢。 - eden881
1
@NullDefault,哇,问题解决了,我已经花了几个小时来处理这个。 - Daniel

25

"allowedHosts" 设置为 package.json 中的属性对我无效。我不得不将其包裹在一个 options 属性中:

"options": {
    "allowedHosts": ["localhost", ".localhost"],
    "proxy": "https://localhost:3386/"
  }

之后,只需运行npm start就可以解决问题,无需重新安装模块。

更新:根据一些评论和其他答案(特别是Anjul's)的建议,我进行了一些额外的研究。我没有找到支持在package.json中添加"options"条目的文档;然而,我觉得这可能是使用Webpack时的副作用。


2
根据你所做的事情,这可能是最佳解决方案。 - TMB
1
这是唯一对我有效的解决方案,谢谢。 - Sksaif Uddin
1
这个解决方案对我有效,但是我注意到“.localhost”不是必需的。 - Leejjon
@Leejjon 我怀疑.localhost条目是有价值的,如果你想允许子域名,比如www - Bill Horvath
我非常讨厌webpack,与webpack的友谊已经结束,vite是我的新朋友。 - Bob the Builder
1
@BillHorvath,这对我有效,谢谢。 - Daniel

18

一种快速解决方法是使用 react-scripts 将您的 webpack 版本进行降级。

在您的 React 应用程序的 package.json 文件中,更改 react-scripts 版本。

替换

"react-scripts": "5.*", 

"react-scripts": "4.0.3",

删除 node_modules 并重新安装包以修复你的 React 应用程序。


不错的解决方案,让我们等待这个问题在v5中得到修复。 - enginbilici
2
@enginbilici 5.0.1 没有修复 :-( - Mo.
使用这个解决方案启动开发服务器时,我得到了“Error:spawn mozilla ENOENT”的错误。 - Emanuele Paolini
这不是适用于所有人的解决方案,只适用于那些恰好使用 react-scripts 作为其Webpack配置的人。 - vsync

10

运行 npm audit fix --force,并确保连接到互联网上
然后运行 npm start
应该可以正常工作


1
它破坏了我的 package.json 文件。 - shaheb

6

对于我来说,删除package-lock.jsonnode_modules文件夹,然后运行npm i解决了这个问题。


5

对我来说,回退至旧版本的node解决了问题。 首先清除npm的缓存,并安装旧版本的node。

    > sudo npm cache clean -f
    > sudo npm install -g n
    > sudo n <version>

最新的18版对我来说无法使用;而之前我一直使用的14.8.2版可以使用。你可以尝试任何低于18版的版本。


4

我刚在JS调试器中调试了该问题。

Node v18更改了os.networkInterfaces()family属性:

v18.0.0
现在,family属性返回数字而不是字符串。

这导致了react-scripts使用的address模块检查"family"是否与"IPv4"匹配出错。


2
所以,我的团队遇到了同样的问题,出现了相同的错误:options.allowedHosts [0]应该是一个非空字符串。我们下面概述的解决方案是一个非常具体的错误,很可能不适用于许多人。
在我们的情况下,allowedHosts[0]变量未定义,我们将allowedHosts[0]变量追踪到node_modules \ react-scripts \ config \ webpackDevServer.config.js中的allowedHost相等。
module.exports = function (proxy, allowedHost) {
  const disableFirewall =
    !proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true';
  return {
    // WebpackDevServer 2.4.3 introduced a security fix that prevents remote
    // websites from potentially accessing local content through DNS rebinding:
    // https://github.com/webpack/webpack-dev-server/issues/887
    // https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
    // However, it made several existing use cases such as development in cloud
    // environment or subdomains in development significantly more complicated:
    // https://github.com/facebook/create-react-app/issues/2271
    // https://github.com/facebook/create-react-app/issues/2233
    // While we're investigating better solutions, for now we will take a
    // compromise. Since our WDS configuration only serves files in the `public`
    // folder we won't consider accessing them a vulnerability. However, if you
    // use the `proxy` feature, it gets more dangerous because it can expose
    // remote code execution vulnerabilities in backends like Django and Rails.
    // So we will disable the host check normally, but enable it if you have
    // specified the `proxy` setting. Finally, we let you override it if you
    // really know what you're doing with a special environment variable.
    // Note: ["localhost", ".localhost"] will support subdomains - but we might
    // want to allow setting the allowedHosts manually for more complex setups
    allowedHosts: disableFirewall ? 'all' : [allowedHost],

urls.lanUrlForConfig 是从 node_modules\react-scripts\scripts\start.js 传递到 allowedHost 的配置文件中。

const createDevServerConfig = require('../config/webpackDevServer.config');
...
createDevServerConfig(proxyConfig, urls.lanUrlForConfig)

urls.lanUrlForCofig是在node_modules\react-dev-utils\WebpackDevServerUtils.js中的prepareUrls函数生成的。

const urls = prepareUrls(
  protocol,
  HOST,
  port,
  paths.publicUrlOrPath.slice(0, -1)
);

prepareUrls函数中,如果计算机的IPv4地址不是私有地址,则将urls.lanUrlForConfig设置为未定义,如下所示:
try {
  // This can only return an IPv4 address
  lanUrlForConfig = address.ip();
  if (lanUrlForConfig) {
    // Check if the address is a private ip
    // https://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
    if (
      /^10[.]|^172[.](1[6-9]|2[0-9]|3[0-1])[.]|^192[.]168[.]/.test(
        lanUrlForConfig
      )
    ) {
      // Address is private, format it for later use
      lanUrlForTerminal = prettyPrintUrl(lanUrlForConfig);
    } else {
      // Address is not private, so we will discard it
      lanUrlForConfig = undefined;
    }
  }
} catch (_e) {
  // ignored
}

因此,最终我们确定出现错误的原因是由于机器获取的IP地址是非私有的,这是由于某些以太网电缆配置导致的(我们得到了一个169.地址,即APIPA地址,因为机器无法连接到DHCP服务器)。这导致urls.lanUrlForConfig未定义,最终会传递到allowedHosts[0]变量并引起错误。
修复无法连接到DHCP服务器的问题本身就是另一个问题,但作为开发目的的临时解决方法,我们在.env文件中添加了DANGEROUSLY_DISABLE_HOST_CHECK=true,并在重新启动开发服务器后它正常工作。在我们的package.json中设置"allowedHosts": "all"也是另一种解决方案。

2
为了解决这个问题,您需要做的是在运行 npm start 时保持互联网连接。请注意,不要删除任何 HTML 标签。

这对我很有帮助,我的问题是我连接到了“CoxWifi”,所以有些互联网可以使用,但这可能会阻止npm需要的任何内容...连接到正确的wifi解决了这个问题。 - sirclesam

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