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.
环境变量在构建期间是被嵌入进去的。因为Create React App提供了静态的HTML/CSS/JS打包,不能在runtime时被读取到。为了在runtime期间读取到环境变量,你需要还在HTML到服务器的内存,并且在运行时替换占位符,就像这里描述的这样:Injecting Data from the Server into the Page。另外你可以在任何你更改他们的时间里重新构建应用。
我们这里同样也有一个内建的叫做NODE_ENV的环境变量。你可以通过process.env.NODE_ENV去读取它。当你运行npm start时,NODE_ENV的值是development,当你运行npm test时,NODE_ENV的值是test,而且当你运行npm run build构建生产环境的包的时候,它通常是production。你不能的手动覆盖NODE_ENV。这样可以预防开发者错把开发环境的代码部署到生产环境。
这篇文章其实也可以叫做:使用create-react-app生成的项目如何配置代理服务器?
在npm-configuration中,有如下解释:
这个proxy字段目前我只了解到可以与create-react-app的react-scripts结合使用:Proxying API Requests in Development,react-scripts应该是基于HTTP_PROXY环境变量做了一些封装。
阅读完本文,你将有一以下收获:
主要分为3部分:
开发过程中的Proxy API 请求设置
人们通常从将服务于后端实现的host和port,同样也为前端react应用提供服务。 例如,在一个应用部署后,生产配置类似下面这样:
但其实这样的设置不是必须的。然而,如果你确实有一个这样的设置,在不考虑重定向它们到其他的host和port开发环境下,那么写出像fetch('/api/todos')这样的请求时正常的。
为了告诉开发环境的服务器去代理任何开发环境中未知的请求到我们自己的api服务器,添加一个proxy到package.json的字段,例如:
使用这种形式的话,当你在开发环境中使用fecth('api/todos')的时候,开发环境的服务器将识别出这不是一个静态资源,然后将代理转发你的请求到http://localhost:4000/api/todos 作为一个回调。生产环境服务器只能代理没有text/html在Accept头中的请求。
方便的是,这就避免了CORS问题以及类似像下面这样的错误信息。
要知道proxy只有在开发环境中会有副作用,而且类似/api/todos 这样的URL在生产环境中是否指向正确取决于我们。你不需要使用/api前缀。任何没有text/html请求头的未识别的请求将会被代理到配置的服务器。
proxy选项支持HTTP,HTTPS以及WebSocket连接。 如果proxy选项还不够灵活的话,你可以去做自定义:
工科男的执着:) 为了更好的说明问题,我们来做一次本地实验:
请求发送:"http://localhost:3000/foo" 错误信息:404
我们为package.json新增proxy服务器:
ctrl + s 热更新react代码后,没有生效,依旧报404的错误。
npm run start 重启本地服务后,代理服务器生效,返回正常的数据。
实现了自动将"http://localhost:3000" 请求转发到"http://0.0.0.89:7300" 的服务器。
不知道聪明的你们发现没有,我们并没有遇到CORS问题,因为在浏览器眼里,我们还是将请求发送到"http://localhost:3000" 中的,它并不知道creat-react-app已经将请求转发到了"http://0.0.0.89:7300" 这个所谓的会触发浏览器CORS安全策略的其他Origin。
天真的浏览器:
请求发送路径: "http://localhost:3000" →"http://0.0.0.89:7300/foo"
响应返回路径: "http://0.0.0.89:7300/foo" →"http://localhost:3000" 备注: 1.此处需要重新运行npm run start 重启本地服务,否则在package.json中设置的proxy不会被检测到并生效。 2.此处的服务器可以是公司内网某台虚拟机上的启动的node服务,也可以是easy-mock等mock服务器(仅支持公司内网部署版,大搜车公网线上服务器不支持)。
因此我们得出一个结论:
实验成功!
手动配置proxy
如果proxy的默认配置不够灵活,可以在package.json自定义一个像下面这样形式的对象。 你也可以http-proxy-middleware或者http-proxy去实现。
所有与这个路径相互匹配的请求将被代理转发。这包括了text/html类型的请求,这种类型是标准proxy选项不支持的。
如果你需要配置多个代理,你需要在定义几个入口。匹配规则还是那样,这样你才能使用正则匹配多个路径。
工科男的执着,继续来做一个实验:
依然使用上面的my-app项目,proxy配置如下:
代码如下:
执行结果: api接口和之前一致,我们这里主要看重定向的foo接口。
请求发送路径: "http://localhost:3000" →"http://0.0.11.22:8848/foo" →"http://0.0.11.22:8848/foo/beta"
响应返回路径: "http://0.0.11.22:8848/foo/beta" →"http://localhost:3000"
可以配置对个代理,我们此处使用的是"http://0.0.0.89:7300" 和"http://0.0.11.22:8848" 这个两台代理服务器,其中 "http://0.0.0.89:7300" 提供了api接口,"http://0.0.11.22:8848" 提供了foo接口。而且我们可以在代理服务器上重定向接口。
因此我们得出一个结论:
实验成功!
环境变量式配置proxy
react的项目可以使用已经声明好的环境变量,这些变量就像是在你的js文件中定义的本地变量一样。默认情况下,已经有NODE_ENV默认环境变量,以及其他的以REACT_APP_为前缀的环境变量。
环境变量在构建期间是被嵌入进去的。因为Create React App提供了静态的HTML/CSS/JS打包,不能在runtime时被读取到。为了在runtime期间读取到环境变量,你需要还在HTML到服务器的内存,并且在运行时替换占位符,就像这里描述的这样:Injecting Data from the Server into the Page。另外你可以在任何你更改他们的时间里重新构建应用。
这些环境变量将被定义在process.env。例如,有一个名叫REACT_APP_SECRET_CODE的环境变量,它可以通过process.env.REACT_APP_SECRET_CODE暴露在我们的javascript文件中。
我们这里同样也有一个内建的叫做NODE_ENV的环境变量。你可以通过process.env.NODE_ENV去读取它。当你运行npm start时,NODE_ENV的值是development,当你运行npm test时,NODE_ENV的值是test,而且当你运行npm run build构建生产环境的包的时候,它通常是production。你不能的手动覆盖NODE_ENV。这样可以预防开发者错把开发环境的代码部署到生产环境。
这些环境变量可以用于根据项目的部署位置或使用超出版本控制的敏感数据来有条件地显示信息。
首先,你需要一个已经定义的环境变量。例如,你想在form表单中控制一个secret变量。
在构建期间,process.env.REACT_APP_SECRET_CODE将会被环境变量中的当前值替代。谨记NODE_ENV是自动设置的变量。
当你在浏览器查看input时,它已经被设置成了abcde(或者是空)。 上面的表单从环境变量中搜索一个名叫REACT_APP_SECRET_CODE的变量。为了使用这个值,我们需要将其定义在环境中。使用两种方式可以做到,一种是在shell中定义,一种是.env文件中。
可以通过NODE_ENV去对一些操作进行控制:
当你使用npm run build编译app时,将会使文件变得更小。
在HTML中引用环境变量:
你可以在public/index.html中获取到以REACT_APP_为前缀的环境变量。例如:
注意事项:
在shell中添加临时的环境变量 对于不同的操作系统,环境变量的设置是不同的。但是更加需要注意的是,这是创建变量的方式仅仅是当前shell session窗口有效。
Linux和macOS(Bash)
还有一种创建.env文件定义环境变量的方式。
.env文件将被检如源代码控制。
其他.env文件将怎么使用?
使用dotenv-expand
在.env文件内部也可以使用变量:
工科男的执着:) 简单做个实验:
键入:
代码:
实验结果:
实验结果并不总是令人满意,问题在于不知道在何处require('dotenv').config(),可能需要在node层引入,也可能需要借助webpack之类的工具,使得view层能访问到。
实验失败。 做一下总结:
充实的一天!