Skip to main content

在开发中代理 API 请求

注意:react-scripts@0.2.3 及更高版本提供此功能。

¥Note: this feature is available with react-scripts@0.2.3 and higher.

人们通常使用与后端实现相同的主机和端口来为前端 React 应用提供服务。

¥People often serve the front-end React app from the same host and port as their backend implementation.

例如,部署应用后,生产设置可能如下所示:

¥For example, a production setup might look like this after the app is deployed:

/             - static server returns index.html with React app
/todos - static server returns index.html with React app
/api/todos - server handles any /api/* requests using the backend implementation

不需要这样的设置。但是,如果你确实有这样的设置,那么编写像 fetch('/api/todos') 这样的请求会很方便,而不必担心在开发过程中将它们重定向到另一个主机或端口。

¥Such setup is not required. However, if you do have a setup like this, it is convenient to write requests like fetch('/api/todos') without worrying about redirecting them to another host or port during development.

要告诉开发服务器将任何未知请求代理到开发中的 API 服务器,请将 proxy 字段添加到 package.json,例如:

¥To tell the development server to proxy any unknown requests to your API server in development, add a proxy field to your package.json, for example:

  "proxy": "http://localhost:4000",

这样,当你在开发中 fetch('/api/todos') 时,开发服务器会识别它不是静态资源,并将你的请求代理到 http://localhost:4000/api/todos 作为后备。开发服务器只会尝试将 Accept 标头中没有 text/html 的请求发送到代理。

¥This way, when you fetch('/api/todos') in development, the development server will recognize that it’s not a static asset, and will proxy your request to http://localhost:4000/api/todos as a fallback. The development server will only attempt to send requests without text/html in its Accept header to the proxy.

方便的是,这在开发中避免了 CORS 问题 和这样的错误消息:

¥Conveniently, this avoids CORS issues and error messages like this in development:

Fetch API cannot load http://localhost:4000/api/todos. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

请记住,proxy 仅在开发中有效(使用 npm start),你需要确保像 /api/todos 这样的 URL 指向生产中的正确内容。你不必使用 /api 前缀。任何没有 text/html 接受标头的无法识别的请求将被重定向到指定的 proxy

¥Keep in mind that proxy only has effect in development (with npm start), and it is up to you to ensure that URLs like /api/todos point to the right thing in production. You don’t have to use the /api prefix. Any unrecognized request without a text/html accept header will be redirected to the specified proxy.

proxy 选项支持 HTTP、HTTPS 和 WebSocket 连接。

¥The proxy option supports HTTP, HTTPS and WebSocket connections.

如果 proxy 选项对你来说不够灵活,你也可以:

¥If the proxy option is not flexible enough for you, alternatively you can:

配置代理后出现 "主机头无效" 错误

¥"Invalid Host Header" Errors After Configuring Proxy

当你启用 proxy 选项时,你选择了一组更严格的主机检查。这是必要的,因为让后端对远程主机开放会使你的计算机容易受到 DNS 重新绑定攻击。本文这个问题 中解释了该问题。

¥When you enable the proxy option, you opt into a more strict set of host checks. This is necessary because leaving the backend open to remote hosts makes your computer vulnerable to DNS rebinding attacks. The issue is explained in this article and this issue.

这应该不会影响你在 localhost 上开发,但是如果你像 在这里描述 一样远程开发,你会在启用 proxy 选项后在浏览器中看到这个错误:

¥This shouldn’t affect you when developing on localhost, but if you develop remotely like described here, you will see this error in the browser after enabling the proxy option:

主机标头无效

¥Invalid Host header

要解决此问题,你可以在项目根目录中名为 .env.development 的文件中指定公共开发主机:

¥To work around it, you can specify your public development host in a file called .env.development in the root of your project:

HOST=mypublicdevhost.com

如果你现在重新启动开发服务器并从指定的主机加载应用,它应该可以工作。

¥If you restart the development server now and load the app from the specified host, it should work.

如果你仍然遇到问题,或者如果你使用的是云编辑器等更奇特的环境,你可以通过向 .env.development.local 添加一行来完全绕过主机检查。请注意,这很危险,并且会使你的计算机暴露于来自恶意网站的远程代码执行:

¥If you are still having issues or if you’re using a more exotic environment like a cloud editor, you can bypass the host check completely by adding a line to .env.development.local. Note that this is dangerous and exposes your machine to remote code execution from malicious websites:

# NOTE: THIS IS DANGEROUS!
# It exposes your machine to attacks from the websites you visit.
DANGEROUSLY_DISABLE_HOST_CHECK=true

我们不推荐这种方法。

¥We don’t recommend this approach.

手动配置代理

¥Configuring the Proxy Manually

注意:react-scripts@2.0.0 及更高版本提供此功能。

¥Note: this feature is available with react-scripts@2.0.0 and higher.

如果 proxy 选项对你来说不够灵活,你可以直接访问 Express 应用实例并连接你自己的代理中间件。

¥If the proxy option is not flexible enough for you, you can get direct access to the Express app instance and hook up your own proxy middleware.

你可以将此功能与 package.json 中的 proxy 属性结合使用,但建议你将所有逻辑合并到 src/setupProxy.js 中。

¥You can use this feature in conjunction with the proxy property in package.json, but it is recommended you consolidate all of your logic into src/setupProxy.js.

首先,使用 npm 或 Yarn 安装 http-proxy-middleware

¥First, install http-proxy-middleware using npm or Yarn:

$ npm install http-proxy-middleware --save
$ # or
$ yarn add http-proxy-middleware

接下来,创建 src/setupProxy.js 并将以下内容放入其中:

¥Next, create src/setupProxy.js and place the following contents in it:

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function (app) {
// ...
};

你现在可以根据需要注册代理!下面是使用上述 http-proxy-middleware 的示例:

¥You can now register proxies as you wish! Here's an example using the above http-proxy-middleware:

const { createProxyMiddleware } = require('http-proxy-middleware');

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

注意:你不需要将此文件导入到任何地方。当你启动开发服务器时,它会自动注册。

¥Note: You do not need to import this file anywhere. It is automatically registered when you start the development server.

注意:该文件仅支持 Node 的 JavaScript 语法。确保仅使用受支持的语言功能(即不支持 Flow、ES 模块等)。

¥Note: This file only supports Node's JavaScript syntax. Be sure to only use supported language features (i.e. no support for Flow, ES Modules, etc).

注意:将路径传递给代理函数允许你在路径上使用通配符和/或模式匹配,这比快速路由匹配更灵活。

¥Note: Passing the path to the proxy function allows you to use globbing and/or pattern matching on the path, which is more flexible than the express route matching.