如何在 NodeJS 中實現(xiàn) gRPC 服務?
什么是 gRPC?
gRPC:谷歌遠程過程調(diào)用是谷歌開發(fā)的開源框架。gRPC 允許您為遠程過程調(diào)用定義請求和響應,并通過處理其余部分來減少您的努力。gRPC 的特點:
現(xiàn)代的
快速地
具有低延遲
高效負載均衡
支持串流
插件認證
監(jiān)控數(shù)據(jù)
建立在 HTTP/2 之上
語言無關
教程目標:在 NodeJS 中實現(xiàn) gRPC 服務
我們都知道 NodeJs 有多流行和成功。因此,在本教程中,我們將在 NodeJs 中實現(xiàn) gRPC 服務。我們將構建一個演示應用程序并執(zhí)行 CRUD 操作。因此,事不宜遲,讓我們開始在我們的 NodeJS 應用程序中實現(xiàn) gRPC 服務。
Bacancy 將減少您的開發(fā)困難。相信最好的!相信我們!
如果您正在為您的夢想項目尋找潛在的 NodeJS 開發(fā)人員,請聯(lián)系 Bacancy。我們擁有技術精湛的開發(fā)人員,他們擁有出色的問題解決方法。別想太多!只需聯(lián)系我們并從我們這里聘請 NodeJs 開發(fā)人員!
在 NodeJS 中實現(xiàn) gRPC 服務的步驟
初始化節(jié)點環(huán)境
安裝 gRPC 服務器
grpc:它將安裝 gRPC 服務器
/proto-loader:它將加載 protobuf 文件
uuid:它將為學生創(chuàng)建隨機哈希 ID
現(xiàn)在,創(chuàng)建students.proto、server.js和client.js文件。單個學生項目將具有 - id、name、age 和 coursename。
Students 定義了我們的學生請求消息格式,其中每個消息請求都有一個唯一的id、學生的姓名、學生的年齡以及學生選擇的課程名稱。
在 proto 中定義 StudentService
創(chuàng)建 RPC 服務。所有 CRUD 操作都將在名為 StudentsService 的服務中可用。
news.proto文件的全部代碼如下所示。
語法=“proto3”;服務學生服務{(diào)
rpc GetAllNews (Empty) 返回 (NewsList) {}}消息學生{
字符串 ID = 1;
字符串名稱 = 2;
int32 年齡 = 3;
字符串課程名稱 = 4;}消息空{(diào)}留言學生名單{
重復學生 students = 1;}const grpc = require("@grpc/grpc-js");const PROTO_PATH = "./news.proto";var protoLoader = require("@grpc/proto-loader");常量選項 = {
多頭:字符串,
一個:真實的,
保持大小寫:真實,
枚舉:字符串,
默認值:真,};var packageDefinition =protoLoader.loadSync(PROTO_PATH, options);const newsProto=grpc.loadPackageDefinition(packageDefinition);const {v4:uuidv4}=require(“uuid”)const server = new grpc.Server();讓學生們= [
{編號:“a68b823c-7ca6-44bc-b721-fb4d5312cafc”,名稱:“約翰·博爾頓”,年齡:22歲,課程名稱:“課程1”
},
{編號:“34415c7c-f82d-4e44-88ca-ae2a1aaa92b7”,名稱:“約翰·博爾頓”,年齡:22歲,課程名稱:“課程2”
}, ];server.addService(StudentsProto.StudentService.service, {
getAll: (_, 回調(diào)) => {
回調(diào)(空,{學生});
},});server.bind("127.0.0.1:30043",grpc.ServerCredentials.createInsecure());console.log("服務器運行在 http://127.0.0.1:50051");服務器.start();
首先,我們導入了@grpc/grpc-js和@grpc/proto-loader庫。名為PROTO PATH 的常量變量將保存students.proto文件的位置。稍后,loadSync 方法會將 proto 文件加載到 gRPC 中。loadPackageDefinition方法將加載包定義。之后,為了初始化服務器實例(),我們將調(diào)用 new grpc.server
創(chuàng)建客戶端存根
我們將調(diào)用 Server 的 addService 方法中定義的 getAll 方法作為客戶端的第二個參數(shù),如下所示。
const PROTO_PATH = "./students.proto";const grpc = require("@grpc/grpc-js");var protoLoader = require("@grpc/proto-loader");var packageDefinition=protoLoader.loadSync(PROTO_PATH, {
多頭:字符串,
一個:真實的,
保持大小寫:真實,
枚舉:字符串,
默認值:真,});const StudentService = grpc.loadPackageDefinition(packageDefinition).StudentService;const client = new StudentService(
“本地主機:30043”,
grpc.credentials.createInsecure());
getAll 方法:獲取所有學生
從客戶端變量調(diào)用服務器中的 getAll 方法。
...const 客戶端 = 新服務(
“本地主機:30043”,
grpc.credentials.createInsecure());client.getAll(null, (err, data) => {
如果 (!err) 拋出錯誤
控制臺日志(數(shù)據(jù));});
現(xiàn)在執(zhí)行 client.js 代碼如下:
// 節(jié)點客戶端.js{
學生: [
{編號:“a68b823c-7ca6-44bc-b721-fb4d5312cafc”,名稱:“約翰·博爾頓”,年齡:22歲,課程名稱:“課程1”
},
{編號:“34415c7c-f82d-4e44-88ca-ae2a1aaa92b7”,名稱:“約翰·博爾頓”,年齡:22歲,課程名稱:“課程2”
},
]}
我們已經(jīng)從 gRPC 客戶端成功執(zhí)行了 gRPC 服務方法。導出 NewsService 實例后,您可以將其導入另一個文件以調(diào)用方法。
const PROTO_PATH = "./students.proto";const grpc = require("@grpc/grpc-js");var protoLoader = require("@grpc/proto-loader");var packageDefinition=protoLoader.loadSync(PROTO_PATH, {
多頭:字符串,
一個:真實的,
保持大小寫:真實,
枚舉:字符串,
默認值:真,});const StudentService = grpc.loadPackageDefinition(packageDefinition).StudentService;const client = new StudentService(
“本地主機:30043”,
grpc.credentials.createInsecure());module.exports = 客戶端;
我們現(xiàn)在可以將客戶端導入到不同的文件中。我們將為我們希望采取的每個步驟制作一個單獨的文件。我們將創(chuàng)建一個名為 get test.js 的文件,該文件導入客戶端并調(diào)用 getAll 方法。
// 測試.jsconst client = require("./client");client.getAll(null, (err, data) => {
如果 (!err) 拋出錯誤
控制臺日志(數(shù)據(jù));});
插入學生記錄
為插入數(shù)據(jù)創(chuàng)建一個新方法。打開 proto 文件并在服務下,您可以添加一個帶有新方法名稱的 RPC。在這里,我們的方法名稱是 Insert under StudentService 服務,如下所示。
該服務將接受 Student 消息并返回新的 Student 對象。
...server.addService(StudentsProto.StudentService.service, {
getAll: (_, 回調(diào)) => {
回調(diào)(空,{學生});
},
插入:(調(diào)用,回調(diào))=> {
讓 Student = call.request;
Student.id = uuidv4();
Students.push(學生);
回調(diào)(空,新聞);
},});...
刪除學生
現(xiàn)在,我們將編寫刪除學生的代碼。這是相同的代碼片段。
...服務學生服務{(diào)
rpc GetAll(空)返回(StudentList){}
rpc 插入(學生)返回(學生){}
rpc 刪除(學生)返回(學生){}}消息 StudentRequestId {
字符串 ID = 1;}...
在這里,請求是StudentRequestId,它將返回一條空消息。
來自 server.js 的代碼片段如下所示。
...
刪除:(調(diào)用,回調(diào))=> {
讓 existingStudentIndex = Students.findnidex(
n =>n.id == call.request.id);如果(現(xiàn)有學生索引!= -1){
Students.splice(existingStudentIndex,1)
回調(diào)(空,{});
}},...
更新現(xiàn)有學生
為了更新數(shù)據(jù),我們將在原型文件中添加一個方法。
...服務學生服務{(diào)
rpc GetAll(空)返回(StudentList){}
rpc 插入(學生)返回(學生){}
rpc 刪除(學生)返回(學生){}
rpc 更新(學生)返回(學生){}}...
該方法接受 Student 消息并使用編輯后的 News 對象進行響應。更新學生數(shù)據(jù)的代碼如下所示。
...
更新:(調(diào)用,回調(diào))=> {
讓 existingStudent = Students.find(n=> n.id== call.request.id);
如果(現(xiàn)有學生){
existingStudent.name = call.request.name;
existingStudent.age = call.request.age;
existingStudent.CourseName =call.request.CourseName;
回調(diào)(空,現(xiàn)有學生);},...
得到一個學生
讓我們在 proto 文件中設置一個方法:
...服務學生服務{(diào)
rpc GetAll(空)返回(StudentList){}
rpc 獲?。▽W生)返回(學生){}
rpc 插入(學生)返回(學生){}
rpc 刪除(學生)返回(學生){}
rpc 更新(學生)返回(學生){}}...
Get 方法需要 ID 作為請求消息并返回 Student 消息。這是 server.js 文件中的實現(xiàn):
...
得到:(調(diào)用,回調(diào))=> {
讓 Student = Students.find(n=>n.id == call.request.id)
如果(學生)= {
回調(diào)(空,學生);}
},...
我們從調(diào)用參數(shù)對象中獲取 id。id 用于從 Students 數(shù)組中檢索相應的學生項目。使用作為參數(shù)傳遞的檢索到的學生項目調(diào)用回調(diào)函數(shù),這使得客戶端獲取學生項目。
// 測試.js// 獲取所有消息const client = require("./client");client.getAll({}, (error, students) => {
如果(錯誤)拋出錯誤;
控制臺日志(學生);});//添加一個學生客戶.插入(
{
name: "標題新聞3",
年齡:11歲,
CourseName: "這里是圖片地址",
},
(錯誤,學生)=> {
如果(錯誤)拋出錯誤;
console.log("成功創(chuàng)建學生。");
});// 編輯學生客戶端.更新(
{
編號:“a68b823c-7ca6-44bc-b721-fb4d5312cafc”,
name: "標題新聞3",
年齡:11歲,
CourseName: "這里是圖片地址",
},
(錯誤,學生)=> {
如果(錯誤)拋出錯誤;
console.log("成功更新一個學生。");
});//刪除一個學生客戶.刪除(
{
編號:“34415c7c-f82d-4e44-88ca-ae2a1aaa92b7”,
},
(錯誤,學生)=> {
如果(錯誤)拋出錯誤;
console.log("成功刪除學生記錄。");
});
現(xiàn)在,運行文件:
使用 Http 服務器
我們現(xiàn)在已經(jīng)構建并準備好了服務器、原型和客戶端。將 Node 服務器附加到 client.js,以便我們服務器中的端點將調(diào)用gRPC新聞服務中的過程。這是端點。
/GET 端點將調(diào)用 getAll 子例程以獲取數(shù)據(jù)庫中的所有學生。
/save POST 端點將調(diào)用插入子例程來創(chuàng)建新的學生項目。
/update PUT 將調(diào)用更新子例程來編輯/更新學生項目。
/remove DELETE 將調(diào)用刪除子例程來刪除學生項目。
這是 Nodejs 中的代碼:
const client = require("./client");const express = require("快遞");const bodyParser = require("body-parser");const app = express();app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: false }));app.get("/", (req, res) => {
client.getAll(null, (err, data) => {
如果(!錯誤){
重新發(fā)送(數(shù)據(jù)。學生)
}
});});app.post("/保存", (req, res) => {
console.log(req.body.CourseName)
讓新學生={
名稱:req.body.name,
年齡:req.body.age,
課程名稱:req.body.CourseName
};
client.insert(newStudent, (err, data) => {
如果(錯誤)拋出錯誤;res.send({data:data, msg:"學生創(chuàng)建成功"})
});});app.post("/update", (req, res) => {
const updateStudent = {
id: req.body.id,
名稱:req.body.name,
年齡:req.body.age,
課程名稱:req.body.CourseName
};
client.update(updateStudent, (err, data) => {
如果(錯誤)拋出錯誤;
res.send({msg:"學生更新成功"})
});});app.post("/remove", (req, res) => {
client.remove({ id: req.body.Student_id }, (err, _) => {
如果(錯誤)拋出錯誤;
console.log("學生刪除成功");
//res.redirect("/");
res.send({msg:"學生刪除成功"})
});});常量端口 = 3000;app.listen(PORT, () => {
console.log("服務器運行在端口 %d", PORT);});
結論
所以,這是關于我們?nèi)绾卧?NodeJS 中實現(xiàn) gRPC 服務。我希望您閱讀本教程的目的對您有所幫助。如果您是 NodeJS 愛好者,請隨時訪問NodeJS 教程頁面并了解有關 Node.js 的更多信息。我們始終樂于接受建議和反饋。如果您有任何問題,請給我們回信。Bacancy 擁有擁有基礎和高級知識的最佳 NodeJS 開發(fā)人員;聯(lián)系我們?yōu)槟膽贸绦蚱刚?NodeJs 開發(fā)人員。
言鼎科技主做軟件開發(fā),微信小程序,網(wǎng)站開發(fā),軟件外包,手機APP開發(fā)。如有需要記得聯(lián)系我們!