系統在此應用程序堆棧溢出_從部署我的第一個完整堆棧Web應用程序中學到的經驗教訓...

系統在此應用程序堆棧溢出

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/

系統在此應用程序堆棧溢出

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/394671.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/394671.shtml
英文地址,請注明出處:http://en.pswp.cn/news/394671.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

const 常量_條款03:盡可能使用const

const 允許你指定一個語義約束(也就是指定一個“不該被改動”的對象),而編譯器會強制實施這項約束。1、const指針如果關鍵字const出現在星號左邊,表示被指物是常量;如果出現在星號右邊,表示指針自身是常量&…

javascript高級程序設計---js事件思維導圖

繪制思維軟件與平時用的筆記,以及導出功能,這三個問題綜合起來,于是我把思維導圖分開畫 1、js事件的基本概念 2、js事件的事件處理程序 3、js事件的事件對象 轉載于:https://www.cnblogs.com/Jamie1032797633/p/10567419.html

jq挑戰30天——打字機效果+小程序

<!doctype html><html><head><meta charset"utf-8"><title>基于jQuery實現的打字機效果-jq22.com</title><script src"http://libs.baidu.com/jquery/1.11.3/jquery.min.js"></script><style></…

和 Thrift 的一場美麗邂逅

一. 與 Thrift 的初識 也許大多數人接觸 Thrift 是從序列化開始的。每次搜索 “java序列化” “方式”、“對比” 或 “性能” 等關鍵字時&#xff0c;搜索引擎總是會返回一大堆有關各種序列化方式的使用方法或者性能對比的結果給你&#xff0c;而其中必定少不了 Thrift&#…

instagram技術_Instagram9位科技女孩進行技術采訪的主要技巧

instagram技術by Rachel通過瑞秋 Instagram9位科技女孩進行技術采訪的主要技巧 (Top tips for technical interviews from nine of Instagram’s tech girls) My job-hunt came to an end a few weeks ago. After endless phone interviews, coding challenges, and on-sites,…

彈出框 每次打開 滾動條置頂_微信置頂文字怎么弄?微信置頂一句話教程

今日支付寶紅包支付寶首頁搜索511501453馬上領取紅包(支付寶雙十二活動&#xff0c;瓜分15億紅包)(領取后一定要記得使用&#xff0c;不然會浪費的呦&#xff0c;更會影響第二天的領取&#xff01;)奶思靚機“ 一 個 有 用 的 公 眾 號 の ”嗨&#xff0c;最近很流行在微信上面…

Python學習_字符串格式化

#!/usr/bin/env python # -*- coding:utf-8 -*-# 百分號格式化 # %[(name)[flags][width].[precision]]typecode # name : 指定占位符的key # flags : - 空格 0 # width : 寬度 # precision : 小數點后保留的位數 # typecode : 必需,數據類型 # 字符串里面有%的時候, %%表示一…

python 3 面向過程編程

python 3 面向過程編程 核心是過程&#xff08;流水線式思維&#xff09;&#xff0c;過程即解決問題的步驟&#xff0c;面向過程的設計就像設計好一條工業流水線&#xff0c;是一種機械式的思維方式。 1、優點&#xff1a;程序結構清晰&#xff0c;可以把復雜的問題簡單化&…

在ionic/cordova中使用百度地圖插件

在ionic項目中&#xff0c;如果想實現定位功能&#xff0c;可以使用ng-cordova提供的cordova-plugin-geolocation。 但由于高墻的緣故&#xff0c;國內andorid環境下&#xff0c;此插件不起作用&#xff08;ios環境下可用&#xff09;。 國內比較好的是現實使用百度地圖提供的A…

django國際化與html語言,Django 國際化

Django 國際化Django 支持國際化&#xff0c;多語言。Django的國際化是默認開啟的&#xff0c;如果您不需要國際化支持&#xff0c;那么您可以在您的設置文件中設置 USE_I18N False&#xff0c;那么Django會進行一些優化&#xff0c;不加載國際化支持機制。NOTE: 18表示Intern…

mongo 刪除節點_將生產節點/ Express Mongo App部署到AWS —反思

mongo 刪除節點在AWS中部署生產Web應用程序的經驗教訓 (Lessons learned deploying a production web application in AWS) 背景 (Background) This is not a code-based tutorial. It consists of all the things I wish I knew before I started the project and the steps I…

漢諾塔問題遞歸算法python代碼_[python]漢諾塔問題遞歸實現

一、問題描述及算法步驟 漢諾塔問題的大意是有三根柱子a, b, c&#xff0c;現在a柱有N個盤子從下往上尺寸遞減排列&#xff0c;要求&#xff1a; 1. 將a上的盤子移動到c柱上; 2. 每次移動一個盤子; 3. 柱子上的盤子始終必須是大的在下面image.png 漢諾塔問題的經典實現算法步驟…

【硬件】PCB設計步驟

前言 合理的PCB設計步驟&#xff0c;可以減少反復修改的可能性。動手設計PCB前&#xff0c;需要按步就班準備一些資料&#xff0c;即使是小項目。 本文將講解如何一次性成功地設計一款PCB的常規步驟。 當然&#xff0c;如果是一個系統&#xff0c;則需要按照瀑布式的思路&#…

linux install StarDict

1.  sudo apt-get install stardict 2.  Downloads from: http://abloz.com/huzheng/stardict-dic/zh_CN/ 3.  tar jxf stardict-21shijishuangxiangcidian-2.4.2.tar.bz2 -C /usr/share/stardict/dic (etc other dictionaries)轉載于:https://www.cnblogs.com/HurryXin/…

交付方式 saas_我在全職工作時如何交付我的第一個SaaS副項目

交付方式 saasby Tigran Hakobyan由Tigran Hakobyan 我在全職工作時如何交付我的第一個SaaS副項目 (How I shipped my first SaaS side-project while working full-time) This is my personal story of how I shipped my very first SaaS side-project while working full-ti…

nginx搭建基于http協議的視頻點播服務器

1&#xff0c;于由自己的服務器上已經安裝好nginx(具體安裝方法見我的另一篇文章&#xff0c;Linux中安裝nginx)&#xff0c;所以不再安裝。 2&#xff0c;下載nginx_mod_h264_streaming-2.2.7.tar.gz(自己在網上搜吧)。 3&#xff0c;安裝pcre&#xff0c;先看有沒有安裝。 [r…

plsql 批量調存儲過程_數控雙端開榫機:批量銑榫頭真牛氣

數控雙端開榫機主要用于實木家具批量化銑榫頭專用&#xff0c;因為其本身的優勢逐漸被家具廠老板們所接受&#xff0c;是目前家具生產不可缺少的一款自動化設備&#xff0c;給企業節約了生產成本&#xff0c;今天又焦峰小編來給大家講解一下。主要技術參數&#xff1a;知乎視頻…

c 向html頁面傳值,html頁面之間的傳值,獲取元素和方法的調用

這篇文章是自己在項目中遇到&#xff0c;同時參考了網上的資料&#xff0c;作為筆記參考使用一、頁面之間的傳值1、使用cookie傳值封裝簡單使用&#xff1a;//獲取cookiefunction getCookie(name){var arr,regnew RegExp("(^| )"name"([^;]*)(;|$)");if(ar…

Codeforces Round #364 (Div. 1) (差一個后綴自動機)

B. Connecting Universities 大意: 給定樹, 給定2*k個點, 求將2*k個點兩兩匹配, 每個匹配的貢獻為兩點的距離, 求貢獻最大值 單獨考慮每條邊$(u,v)$的貢獻即可, 最大貢獻顯然是左右兩側點的最小值. #include <iostream> #include <algorithm> #include <cstdio&…

Python黑魔法

1. 賦值 In [1]: x 1...: y 21...: print x, y...: ...: x, y y, x...: print x, y 1 21 21 1 2. 列表合并 In [2]: a1 [(2,3),(3,4)]...: a2 [(4,5)]...: a a1 a2...: print a [(2, 3), (3, 4), (4, 5)] 3. 字典合并 方式1: In [3]: d1 {a: 1}...: d2 {b: 2}...: ...…