目录
Same origin policy and CORS
Application to the Internet
Frontend production build
Serving static files from the backend
Streamlining deploying of the frontend
Proxy
接下来,将之前制作的前端连接到我们自己的后端。
前面的部分中,前端可以从作为后端的 json 服务器向地址 http://localhost:3001/notes 索取便笺列表。
现在后端有一个稍微不同的 url 结构,便笺可以从 http://localhost:3001/api/notes 中获取到。
修改 src/services/notes.js 中的baseUrl属性 :
import axios from 'axios'
const baseUrl = 'http://localhost:3001/api/notes'
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
// ...
export default { getAll, create, update }
现在前端的 GET 请求由于某些原因不能工作: http://localhost:3001/api/notes:
但是可以从浏览器和Postman访问后端,没有任何问题。
【同源政策和 CORS】
问题出在一个叫 CORS 的东西上,或者叫跨来源资源共享。
根据维基百科 :
Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts) on a web page to be requested from another domain outside the domain from which the first resource was served. A web page may freely embed cross-origin images, stylesheets, scripts, iframes, and videos. Certain "cross-domain" requests, notably Ajax requests, are forbidden by default by the same-origin security policy.
Cross-origin resource sharing (CORS)是一种机制,它允许一个网页上受限制的资源(例如字体),从提供一手资源的域名以外的另一个域名请求跨来源资源共享。 一个网页可以自由地嵌入跨来源的图片、样式表、脚本、 iframe 和视频。 默认情况下,同源安全策略禁止某些“跨域”请求,特别是 Ajax 请求。
这里问题在于,默认情况下,运行在浏览器应用的 JavaScript 代码只能与相同源的服务器通信。
因为服务器位于本地主机端口3001,前端位于本地主机端口3000,所以它们不具有相同的源。
同源策略和 CORS 并不是特定于 React 或 Node 的,它实际上是 web 应用操作的通用原则。
我们可以通过使用 Node 的 cors 中间件来允许来自其他源的请求。
安装cors
npm install cors
使用中间件并允许来自所有来源的请求:
const cors = require('cors')
app.use(cors())
现在前端工作正常了!但是,在后端还没有实现更改便笺重要性的功能。
【将应用部署到网上】
现在整个栈已经准备就绪,现在将应用迁移到互联网上。 我们将使用古老的 Heroku https://www.Heroku.com 。
如果您以前从未使用过 Heroku,您可以从Heroku 文档或通过谷歌搜索找到指令。
向项目的根目录添加一个名为 Procfile的文件,告诉 Heroku 如何启动应用。
web: npm start
更改应用在index.js 文件底部使用的端口定义,如下所示:
const PORT = process.env.PORT || 3001app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`)
})
现在我们使用定义在环境变量的端口,如果环境变量 PORT 是未定义的,则使用端口3001。
Heroku 会在环境变量的基础上配置应用端口。
在项目目录中创建一个 Git 仓库,并使用如下内容添加 .gitignore
node_modules
使用命令heroku create创建一个 Heroku 应用,将你的代码提交到仓库并将其推送到Heroku,git push Heroku main。
如果一切顺利,应用就能正常工作:
如果没有运行成功,可以通过使用命令heroku logs 读取 heroku logs 来发现问题。
前端也与 Heroku 的后端一起工作。 可以将前端的后端地址更改为后端在 Heroku 的地址http://localhost:3001。
【前端生产构建】
到目前为止,我们一直在开发模式 中运行 React code。
开发模式下,应用提供清晰的错误消息,立即向浏览器渲染代码更改,等等。
部署应用时,需要创建一个生产构建或一个为生产而优化的应用版本。
使用create-react-app 创建的应用的生产构建可以使用命令npm run build创建。
从前端项目的根目录运行这个命令,将创建一个名为build 的目录(其中包含应用中唯一的 HTML 文件index. HTML) ,其中包含目录static。
应用的 JavaScript 代码的Minified版本将生成到static 目录。 即使应用代码位于多个文件中,所有的 JavaScript 都将被缩小到一个文件中。 应用依赖项的所有代码也将缩小到这个单一文件中。
缩小后的代码可读性不是很好,开头是这样的:
!function(e){function r(r){for(var n,f,i=r[0],l=r[1],a=r[2],c=0,s=[];c
【从后端服务部署静态文件】
部署前端可以将生产构建( build 目录)复制到后端仓库的根目录,并配置后端以显示前端的 main page (文件 build/index.html)作为其主页。
我们从将前端的生产构建复制到后端的根目录。 使用一台Mac 或 Linux 计算机,可以通过命令从前端目录进行复制
cp -r build ../../../osa3/notes-backend
如果你使用的Windows操作系统,你可以使用copy 或者 xcopy 命令。要么就简单地使用复制粘贴即可。
后端目录现在应该如下所示:
为了让 express 显示 static content、 页面 index.html 和它用来fetch的 JavaScript 等等,我们需要一个来自 express 的内置中间件,称为static。
在中间件声明中添加如下内容时
app.use(express.static('build'))
每当 express 收到一个 HTTP GET 请求时,它都会首先检查build 目录是否包含与请求地址对应的文件。 如果找到正确的文件,express 将返回该文件。
现在 HTTP GET 向地址www.serversaddress.com/index.html或 www.serversaddress.com 的GET请求,将显示 React 前端。 Get 请求到地址 www.serversaddress.com/notes 将由后端代码处理。
因为现在的情况下,前端和后端都在同一个地址,所以可以声明 baseUrl 为relative URL,省略声明服务器的部分。
import axios from 'axios'
const baseUrl = '/api/notes'
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
// ...
更改之后,我们必须创建一个新的生产构建,并将其复制到后端存储库的根。
该应用现在可以从后端 地址 http://localhost:3001 中使用:
我们的应用现在的工作方式与我们在第0章节中研究的单页应用 示例应用完全一样。
当我们使用浏览器访问地址 http://localhost:3001 时,服务器从build 仓库返回index. html 文件。 档案的摘要内容如下:
React App