系统在此应用程序堆栈溢出_从部署我的第一个完整堆栈Web应用程序中学到的经验教训...

2023-05-16

系统在此应用程序堆栈溢出

by Will Abramson

威尔·艾布拉姆森(Will Abramson)

从部署我的第一个完整堆栈Web应用程序中学到的经验教训 (Lessons learned from deploying my first full-stack web application)

I recently achieved one of my long-term goals: deploying my first full-stack web application.

我最近实现了我的长期目标之一:部署我的第一个完整堆栈Web应用程序。

In this post, I’ll be sharing the lessons I learned from a beginner’s perspective, along with some useful tutorials I followed, key roadblocks that I had to overcome, and mistakes that I made along the way. I want to help other developers understand what’s involved in deploying a web application.

在这篇文章中,我将分享我从初学者的角度学到的教训,以及我遵循的一些有用的教程,必须克服的主要障碍以及一路走来的错误。 我想帮助其他开发人员了解部署Web应用程序涉及的内容。

After spending over six weeks googling, trying, failing, and trying again, I finally managed to deploy my web application. It was comprised of a Node.js backend along with a React frontend to an Amazon Web Services (AWS) EC2 virtual machine.

经过六个多星期的搜寻,尝试,失败和重试之后,我终于设法部署了Web应用程序。 它由Node.js后端以及Amazon Web Services(AWS)EC2虚拟机的React前端组成。

It was quite a challenge but it was truly satisfying, as in the end the application was successfully deployed and is now accessible via a public domain name.

这是一个很大的挑战,但确实令人满意,因为最终该应用程序已成功部署,现在可以通过公共域名访问。

The biggest difficulty for me was finding the information. I didn’t understand what was involved in deployment. So I struggled to find effective answers on the web. I failed to find a single guide for the whole process.

对我来说最大的困难是查找信息。 我不了解部署中涉及的内容。 因此,我很难在网上找到有效的答案。 我没有找到整个过程的单一指南。

Hopefully, I can simplify the deployment learning curve for the next person by bringing all the information I learned into one place.

希望我可以将我学到的所有信息都放在一个地方,从而简化下一个人的部署学习曲线。

So here it goes…

所以就这样...

部署应用程序意味着什么? (What does it mean to deploy an application?)

A web application is split into two parts.

Web应用程序分为两部分。

  • Client side code: This is your frontend UI code. These are static files that don’t change throughout your application’s life. Static files need to exist somewhere so that your users can download and run them in their browser on the client side. I will go into more detail about where that somewhere might be later.

    客户端代码:这是您的前端UI代码。 这些是静态文件,它们在应用程序的整个生命周期中都不会改变。 静态文件必须存在于某个位置,以便您的用户可以在客户端的浏览器中下载并运行它们。 我将在以后更详细地介绍该位置。

  • Server side code: This deals with all the logic of your application. It should be run on a server (machine), commonly a virtual one like an EC2 instance, much like you run it when developing locally.

    服务器端代码:处理您应用程序的所有逻辑。 它应在服务器(机器)上运行,通常是虚拟服务器(如EC2实例),就像在本地开发时运行它一样。

To run your local code, the server must have a copy of it. I just cloned my Github repo onto the server from the command line interface of the server.

要运行您的本地代码,服务器必须具有它的副本。 我只是从服务器的命令行界面将我的Github存储库克隆到服务器上。

You also need to setup your server. This includes:

您还需要设置服务器。 这包括:

  • setting up the machine to be able to access the internet and run your code

    设置机器以能够访问互联网并运行您的代码
  • exposing the correct ports

    暴露正确的端口

  • listening for HTTP requests (Internet requests)

    侦听HTTP请求(Internet请求)
  • pointing a custom domain name to the server your application is running from

    将自定义域名指向应用程序运行所在的服务器

You’ll know it’s working when you can access your application using your custom domain name from any machine on the Internet and all the functionality of your application is working as expected.

当您可以从Internet上的任何计算机上使用自定义域名访问应用程序并且应用程序的所有功能都按预期运行时,您就会知道它正在工作。

So, that’s an overview. But, how do we actually do it?

所以,这是一个概述。 但是,我们实际上该如何做呢?

入门 (Getting started)

You should split up your application and break down the problem. You are deploying two different things: client-side static files and server-side code.

您应该拆分应用程序并解决问题。 您将部署两种不同的内容:客户端静态文件和服务器端代码。

My first mistake was to think of my application as a whole, rather than two separate applications that talk to each other.

我的第一个错误是将我的应用程序视为一个整体,而不是将两个单独的应用程序相互通信。

This added to the complexity and made googling for answers useless. It left me feeling overwhelmed.

这增加了复杂性,并且使搜​​索变得毫无用处。 这让我感到不知所措。

I broke down the problem into these steps. Although each problem can always be broken down further.

我将问题分解为以下步骤。 尽管可以始终将每个问题进一步分解。

  • Setting up your VM and deploying your Backend

    设置虚拟机并部署后端
  • Deploying your Frontend

    部署前端
  • Getting the Two Applications Communicating

    使两个应用程序进行通信
  • Pointing your Domain Name

    指向您的域名

In the figure below, I’ve attempted to put the complete process in a diagram.

在下图中,我试图将整个过程放在图表中。

设置虚拟机并部署后端 (Setting up your VM and deploying your Backend)

In my case, this was an Express.js server deployed on an amazon EC2 virtual machine. I would’ve explained how to do it, but the tutorial “Creating and Managing a Node.js Server on AWS - Part 1” does a far better job.

就我而言,这是部署在Amazon EC2虚拟机上的Express.js服务器。 我已经解释了如何做到这一点,但是教程“ 在AWS上创建和管理Node.js服务器-第1部分 ”做得更好。

It’s the best tutorial I have come across in this space and covers:

这是我在这个领域遇到的最好的教程,内容包括:

  • Starting an AWS virtual machine

    启动AWS虚拟机
  • Getting up correct security groups for ports

    为端口建立正确的安全组
  • Pulling code from GitHub onto the virtual machine

    将代码从GitHub提取到虚拟机上
  • Running your server

    运行服务器
  • Using Nginx, a HTTP server, to forward requests from port 80

    使用Nginx(HTTP服务器)转发来自端口80的请求
  • Using PM2 to persist the process running your server

    使用PM2保留运行服务器的过程

It was a life saver, and without it I would still probably be stuck. So thank you, Robert Tod.

它可以挽救生命,没有它,我可能仍然会陷入困境。 谢谢罗伯特·托德 ( Robert Tod) 。

You can easily test that your server is running using Postman to send a request to one of your Backend endpoints.

您可以使用Postman向一个后端端点发送请求,轻松测试服务器是否正在运行。

部署前端 (Deploying your Frontend)

So now that you have a server with your backend running (I hope), you need to get your Frontend working. This is really easy when you understand the process.

因此,既然您拥有一台运行后端的服务器(希望如此),则需要使前端工作。 当您了解此过程时,这真的很容易。

Unfortunately, I didn’t for a long time. For example, at the beginning I tried to run my Frontend using npm start.

不幸的是,我没有很长时间了。 例如,在一开始,我尝试使用npm start运行Frontend。

Npm start creates a local development server, serving the files so that they are only accessible using localhost which is not what we want.

Npm start创建一个本地开发服务器,为文件提供服务,以便只能使用不需要的localhost访问文件。

To deploy the Frontend code, you have to store all the files on your virtual machine in a location your web server knows about. The web server lets a client download the code and run it in their browser.

要部署前端代码,您必须将虚拟机上的所有文件存储在Web服务器知道的位置。 Web服务器允许客户端下载代码并在其浏览器中运行。

Apache and Nginx are examples of web servers.

Apache和Nginx是Web服务器的示例。

A web server listens to certain ports, port 80 or more commonly port 443 (secure), and either serves static files (your Frontend code) or passes the request to a different port. For example, we saw a request to the Backend in the Node.js tutorial above.

Web服务器侦听某些端口,端口80或更常见的端口443(安全),并提供静态文件(您的前端代码)或将请求传递到其他端口。 例如,我们在上面的Node.js教程中看到了对后端的请求。

As Frontend code is just a collection of files stored on a web server, we want to make these files as small and optimized as possible. This ensures that the client can download and run them as fast as possible.

由于前端代码只是存储在Web服务器上的文件的集合,因此我们希望使这些文件尽可能小并进行优化。 这样可以确保客户端可以尽快下载并运行它们。

Faster page loads equal happy users.

更快的页面加载速度等于满意的用户。

All your Frontend JavaScript files can be bundled into a single JavaScript file. This is usually done by running npm run build, assuming you have this script defined in your package.json.

您所有的前端JavaScript文件都可以捆绑到一个JavaScript文件中。 假设您在package.json中定义了此脚本,通常可以通过运行npm run build来完成。

You can read more about bundling code here.

您可以在此处阅读有关捆绑代码的更多信息。

Basically, bundling your application removes anything that isn’t essential. This includes shortening names and placing all JavaScript code in one file. It will also compile your code into the correct JavaScript version. This is so all web browsers can understand and run it (for example, converting TypeScript to JavaScript).

基本上,捆绑您的应用程序会删除所有不必要的内容。 这包括缩短名称并将所有JavaScript代码放在一个文件中。 它还会将您的代码编译为正确JavaScript版本。 这样所有的Web浏览器都可以理解和运行它(例如,将TypeScript转换为JavaScript)。

When your code is bundled, you just have to copy the files into your web server. Then configure your web server to serve files stored at that location.

捆绑代码后,只需要将文件复制到Web服务器中。 然后配置您的Web服务器以提供存储在该位置的文件。

Here is a good article on deploying static files to an Nginx web server.Hopefully, if all is going well (which it never does), your Frontend code is now working.

这是一篇关于将静态文件部署到Nginx Web服务器上的好文章 。希望一切顺利(从未实现),您的Frontend代码现在可以正常工作了。

Visit the public DNS for the virtual machine to verify that the static information from the site loads.

访问虚拟机的公共DNS,以验证是否从站点加载了静态信息。

使两个应用程序进行通信 (Getting the Two Applications Communicating)

So I had both my applications running individually, but something wasn’t right. I couldn’t get rid of a network request error.

所以我让我的两个应用程序都单独运行,但是有些不对劲。 我无法摆脱网络请求错误。

This was the most frustrating point for me. I was so close, but I ran into some setbacks that ended up taking weeks to solve.

这是我最沮丧的一点。 我是如此亲密,但遇到了一些挫折,最终需要花费数周的时间才能解决。

Cross-Origin Resource Sharing (CORS) is a mechanism that allows communication between different IP addresses or ports. You want your Backend to be allowed to send data back to your Frontend.

跨域资源共享(CORS)是一种允许不同IP地址或端口之间进行通信的机制。 您希望允许后端将数据发送回前端。

To enable this, your Frontend must include the correct headers when requesting resources. This can be done in two ways:

为此,您的前端在请求资源时必须包含正确的标头。 这可以通过两种方式完成:

  • The headers can be added in Nginx although it takes some figuring out. You can start here.

    头文件可以在Nginx中添加,尽管需要花一些时间。 你可以从这里开始。

  • You can use the cors npm module to include the headers.

    您可以使用cors npm模块包含标头。

A great way to test this if it is working is by looking within the network tab of your browser’s developer tools. This shows all the requests your application is making. If you select a request you can see where the request went to and what headers it included.

测试此功能是否正常的一种好方法是在浏览器开发人员工具的“网络”标签中查看。 这显示了您的应用程序提出的所有请求。 如果选择一个请求,则可以看到该请求的去向及其包含的标题。

Once you have the right request headers being sent with your request, you have to make sure the requests are going to the correct place. This should be the address and port of your EC2 Backend server and not the address and port of your local Backend server like mine was.

将正确的请求标头与请求一起发送后,必须确保将请求发送到正确的位置。 这应该是EC2后端服务器的地址和端口,而不是像我的一样的本地后端服务器的地址和端口。

Your Frontend communicates with your Backend using HTTP requests. Somewhere in your Frontend, code you will tell it where your Backend is located.

您的前端使用HTTP请求与后端进行通信。 在您的前端的某个地方,通过代码可以告诉您后端的位置。

const networkInterface = createNetworkInterface({
 uri: ‘http://0.0.0.0:5000/graphql',
});

Mine looked like this, which clearly was not going to be correct for my production server.

我的看起来像这样,显然对于我的生产服务器来说是不正确的。

Annoyingly this made my application seem like it worked when I first navigated to it on my local machine, as my local server was running and able to return the required information.

令人烦恼的是,当我的本地服务器正在运行并且能够返回所需的信息时,当我第一次在本地计算机上导航到它时,我的应用程序似乎可以正常工作。

To fix this, you can simply change the URI defined, but that means having to change it back every time you do further development, which is not the best approach (I know because I did it).

要解决此问题,您可以简单地更改定义的URI,但这意味着每次进行进一步开发时都必须将其改回来,这不是最好的方法(我知道是因为我这样做了)。

A more sophisticated solution is to include both URIs and use environment variables to select the appropriate one.

一种更复杂的解决方案是同时包含URI和使用环境变量来选择适当的解决方案。

const networkInterface = createNetworkInterface({   
   uri: process.env.NODE_ENV === 'production' ?      
                     'http://thecommunitymind.com/graphql' : 
                     'http://0.0.0.0:5000/graphql',
});

Simple but effective. Just make sure you set your NODE_ENV to production when using it for your production server.

简单但有效。 只需确保将NODE_ENV用于生产服务器时将其设置为生产即可。

We’re almost there. In fact, your deployment might work now.

我们快到了。 实际上,您的部署现在可以工作了。

But I had one last problem to overcome.

但是我还有最后一个需要克服的问题。

Even though my CORS setup was correct, the required headers were not being included consistently and were only getting added sometimes. For some POST requests, the CORS headers were not always present. Very odd!

即使我的CORS设置正确,所需的标头也未始终包括在内,有时只是添加而已。 对于某些POST请求,并不总是存在CORS标头。 很奇怪!

This error lead me on a frustrating goose chase trying to fix my CORS setup in Nginx, when actually it had nothing to do with CORS.

这个错误使我陷入了令人沮丧的追赶中,试图在Nginx中修复我的CORS设置,而实际上与CORS无关。

Actually, I didn’t even need to do anything with CORS in Nginx, because I was using the CORS npm module.

实际上,我甚至不需要在Nginx中对CORS做任何事情,因为我正在使用CORS npm模块。

The error was due to two other issues:

该错误是由于其他两个问题引起的:

  • My database was included as an sqlite file in the Backend and

    我的数据库作为sqlite文件包含在后端中,并且
  • My process manager, PM2, was watching for file changes

    我的流程经理PM2正在监视文件更改

So writing to the database file on a POST request caused PM2 to restart the server. This was leading to the correct headers not getting picked up which resulted in misleading errors.

因此,根据POST请求写入数据库文件会导致PM2重新启动服务器。 这导致未提取正确的标头,从而导致误导性错误。

A great tip and one I wish I had known earlier is to check your server logs on your EC2 instance. Whether you’re using PM2 or something else there will always be a way to check your logs. Just Google it!

我希望早些时候知道的一个很好的技巧是检查EC2实例上的服务器日志。 无论您使用的是PM2还是其他产品,总会有一种检查日志的方法。 只是谷歌而已!

These logs provided the key to solve my issue.

这些日志提供了解决我的问题的关键。

I simply had to turn off the watch ability of PM2. Bingo. And finally, it worked.

我只需要关闭PM2的监视功能即可。 答对了。 最后,它奏效了。

指向您的域名 (Pointing your Domain Name)

This is the icing on the cake. You want a nice clean URL for your newly deployed application.

这是锦上添花。 您希望为新部署的应用程序提供一个简洁的URL。

I bought my domain name through Amazon and used Route 53 to point it to the correct EC2 instance. This was a surprisingly painless experience.

我通过亚马逊购买了域名,并使用Route 53将其指向正确的EC2实例。 这是一个令人惊讶的无痛体验。

Amazon’s tutorial was quite sufficient.

亚马逊的教程就足够了。

摘要 (Summary)

I hope this post has helped you understand the web application deployment process and ultimately get your amazing project online — whatever that may be.

我希望这篇文章能帮助您了解Web应用程序的部署过程,并最终使您的惊人项目联机(无论可能如何)。

At least you should have a better idea of what to Google for!

至少您应该对Google有了更好的了解!

Good Luck.

祝好运。

翻译自: https://www.freecodecamp.org/news/lessons-learned-from-deploying-my-first-full-stack-web-application-34f94ec0a286/

系统在此应用程序堆栈溢出

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

系统在此应用程序堆栈溢出_从部署我的第一个完整堆栈Web应用程序中学到的经验教训... 的相关文章

  • String/StringBuilder/StringBuffer

    String StringBuilder StringBuffer 1 可变性 String 字符串常量 xff0c 字符串是不可变的 源码中 xff1a span class token keyword private span span
  • 计算机网络-网络结构

    计算机网络 三种网络结构 OSI xff1a 物理层 数据链路层 网络层 传输层 会话层 表示层 应用层 TCP IP xff1a 网络接口层 网际层 传输层 应用层 五层 xff1a 物理层 数据链路层 网络层 传输层 应用层 应用层 它
  • 计算机网络-三次握手/四次挥手/可靠传输/ARQ协议

    计算机网络 TCP三次握手 同步SYN 确认ACK 发送端 SYN标志的数据报 seq 61 x gt 接收端 xff08 SYN 61 1 xff09 发送端 lt SYN ACK标志的数据报 seq 61 y ack 61 x 43 1
  • 计算机网络-拥塞控制/HTTP/URL

    滑动窗口和流量控制 TCP利用滑动窗口实现流量控制 xff0c 流量控制就是为了控制发送方发送速率 xff0c 保证接收方来得及接收 接收方发送的确认报文中的窗口字段可以来控制发送方窗口大小 xff0c 从而影响发送方的发送速率 xff0c
  • Integer和int进行==比较

    Integer amp int int是Java的基本数据类型 xff0c 而Integer是它的包装类 xff0c 61 61 在进行比较时 xff0c 如果是基本类型 xff0c 比较的是值 xff0c 如果是引用类型 xff0c 比较
  • deepin恢复出厂设置_如何恢复出厂设置

    deepin恢复出厂设置 There comes a time in every user s life when they have to reset something back to its factory default Perha
  • JUC-JMM/Volatile/单例模式

    JMM Java内存模型 xff0c 是一个概念 xff0c 不存在的东西 xff0c 概念 约定 关于JMM的一些同步约定 xff1a 线程解锁前 xff0c 必须把共享变量刷回主存线程加锁前 xff0c 必须读取主存中的最新值到工作内存
  • 设计模式-六大原则/单例模式

    设计模式 概念 xff1a 是一套被反复使用 多数人知晓的 经过分类编目的 代码设计经验的总结 作用 xff1a 为了可重用代码 让代码更容易被他人理解 保证代码可靠性 程序的重用性 JDK Spring等源码中许多地方用到了设计模式 设计
  • 设计模式-工厂模式/代理模式

    工厂模式 创建对象时不会对客户端暴露创建逻辑 xff0c 并且通过使用一个共同的接口来指向新创建的对象 xff0c 实现创建者和调用者分离 xff0c 工厂模式分为简单工厂 工厂方法 抽象工厂 xff0c Spring中的IOC容器创建be
  • WSL2+VcXsrv 打开图形窗口实现可视化

    前些天有个朋友拜托我帮忙看看 老师让配置的 Cygwin 安装 gnuplot 用 XLaunch 做图形界面 始终画不出图来 这个问题我研一的时候也遇到过 走了许多弯路 所以在电脑上一阵鼓捣 现在做一个如下记录 Cygwin 43 XLa
  • gitlab 安装/卸载/备份/迁移/汉化/重置root密码 全套教程

    服务器环境 centos7 4 gitlab版本 gitlab span class token operator span ce span class token operator span 11 span class token pun
  • bash: line 5: bgzip: command not found

    报错信息 xff1a bash line 5 bgzip command not found 解决方式 xff1a conda install tabix
  • linux之chgrp命令

    chgrp 命令更改 目录或文件所属的组 chgrp R 目录 或 文件 R xff1a 递归式改变指定目录及目录下所有文件和子目录 chgrp eg chgrp group2 file2 将file2的属组更改为group2 以空格分开
  • PageHelper limit自定义位置

    package com sgcc base common rest model import com github pagehelper Page import com github pagehelper dialect helper My
  • Ubuntu20.04 执行nvidia-smi命令,显示不能连接到显卡驱动

    错误 xff1a NVIDIA SMI has failed because it couldn t communicate with the NVIDIA driver 解决这个问题的一般方法 xff1a nvidia smi 报错 xf
  • nginx安装windows服务

    进入nginx安装目录列如 D code nginx 1 6 3 将WinSW NET4 exe复制到 nginx安装目录下 将WinSW NET4 exe重名为install service exe xff0c 并创建立install s
  • 贝塞尔曲线 弯曲动画ios_用贝塞尔曲线弯曲

    贝塞尔曲线 弯曲动画ios by Nash Vail 由Nash Vail 用贝塞尔曲线弯曲 Nerding Out With Bezier Curves Since the past few days I have been trying
  • MySQL随机获取10条数据-多种方式

    MySQL随机获取10条数据 多种方式 测试表有 254 万条数据 xff0c 各个SQL的执行效率如下 方式一 最简单 xff0c 但是效率最低 执行时间 xff1a 9 845s SELECT FROM 96 table 96 ORDE
  • ESXI克隆虚拟主机

    目录 一 通过命令克隆主机 二 通过网页端克隆主机 一 通过命令克隆主机 1 启用esxi的ssh 2 ssh登录esxi 3 找到虚拟机所在目录 4 建立新虚拟机目录 5 拷贝vmx文件 6 克隆vmdk 7 修改vmx文件 8 esxi
  • SqlServer 查询JSON 数据

    https www cnblogs com whitebai p 13614024 html

随机推荐