在开发中代理 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:
在你的服务器 (这是为 Express 做的方法) 上启用 CORS。
¥Enable CORS on your server (here’s how to do it for Express).
使用 环境变量 将正确的服务器主机和端口注入你的应用。
¥Use environment variables to inject the right server host and port into your app.
配置代理后出现 "主机头无效" 错误
¥"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.