基于Protocol Buffers实现Go后端与Dart前端的数据交互

基于protocol buffers实现go后端与dart前端的数据交互

本教程详细介绍了如何利用Protocol Buffers在Go后端对结构化数据进行序列化,并通过Ajax传输至Dart前端进行反序列化。内容涵盖了环境搭建、.proto文件定义、代码生成、Go语言中的数据封装与序列化,以及Dart语言中的数据请求与反序列化,旨在提供一套完整的跨语言数据通信解决方案,确保数据传输的效率与可靠性。

基于Protocol Buffers实现Go后端与Dart前端的数据交互

引言:Protocol Buffers简介

Protocol Buffers(简称Protobuf)是Google开发的一种语言无关、平台无关、可扩展的序列化结构化数据的方法,它比XML和JSON更小、更快、更简单。通过定义数据结构(.proto文件),Protobuf编译器可以自动生成多种编程语言的源代码,用于读写这些结构化数据。这使得在不同语言编写的系统之间进行数据交换变得高效且可靠。本教程将指导您如何在Go后端使用Protobuf序列化数据,并通过HTTP AJAX请求将其发送到Dart前端进行反序列化。

环境搭建与工具准备

在开始之前,您需要安装Protocol Buffers编译器(protoc)以及Go和Dart的Protobuf库。

安装Protocol Buffers编译器 (protoc)protoc是用于编译.proto文件的核心工具。在基于Debian的系统上,您可以通过以下命令安装:

sudo apt-get install protobuf-compiler

对于其他操作系统,请参考Protobuf官方文档进行安装。

立即学习“前端免费学习笔记(深入)”;

安装Go语言Protobuf库Go语言的Protobuf库可以通过Go模块进行安装:

go get google.golang.org/protobuf/cmd/protoc-gen-go google.golang.org/protobuf/cmd/protoc-gen-go-grpc

确保protoc-gen-go和protoc-gen-go-grpc在您的PATH环境变量中,通常Go模块会自动处理。

安装Dart语言Protobuf插件Dart的Protobuf插件用于从.proto文件生成Dart代码。

dart pub global activate protoc_plugin

确保protoc_plugin的执行文件也在您的PATH中,或者知道其确切路径。

定义数据结构:.proto文件

数据传输的核心是.proto文件,它定义了消息的结构。我们将创建一个名为car.proto的文件,其中包含一个Car消息的定义。

// car.protosyntax = "proto2"; // 也可以使用 proto3,根据项目需求选择message Car {    required string make = 1;    required int32 numdoors = 2;}

syntax = “proto2”;:指定使用Protobuf的proto2语法。proto3是更现代的版本,语法更简洁,但proto2在某些场景下提供了required、optional、default等更严格的字段修饰符。message Car { … }:定义了一个名为Car的消息类型。required string make = 1;:定义了一个必需的字符串字段make,字段编号为1。字段编号在消息中必须是唯一的,且一旦定义不应改变,因为它用于序列化和反序列化。required int32 numdoors = 2;:定义了一个必需的32位整数字段numdoors,字段编号为2。

代码生成

定义好.proto文件后,使用protoc工具为Go和Dart生成相应的代码。

在car.proto文件所在的目录下执行以下命令:

# 为Go语言生成代码protoc --go_out=. car.proto# 为Dart语言生成代码protoc --dart_out=. car.proto

执行这些命令后,您将看到在当前目录下生成了car.pb.go和car.pb.dart文件。这些文件包含了Car消息的Go和Dart类定义,以及相关的序列化和反序列化方法。

Go后端数据序列化

在Go后端,我们将创建一个Car对象,将其序列化为二进制数据,并通过HTTP响应发送给前端。

创建Go Car对象生成的car.pb.go文件提供了Car结构体。在Go代码中,您需要使用proto.String和proto.Int32等辅助函数来设置required字段的值。

package mainimport (    "fmt"    "log"    "net/http"    "google.golang.org/protobuf/proto" // 注意:新版本库路径    "./car" // 导入生成的 car.pb.go 文件所在的包,根据实际项目结构调整路径)func main() {    http.HandleFunc("/getCarProto", handleGetCarProto)    fmt.Println("Server started on :8080")    log.Fatal(http.ListenAndServe(":8080", nil))}func handleGetCarProto(w http.ResponseWriter, r *http.Request) {    // 创建一个Car对象    c := &car.Car{        Make:     proto.String("Citroën"),        Numdoors: proto.Int32(4),    }    // 将Car对象序列化为二进制数据    binaryData, err := proto.Marshal(c)    if err != nil {        http.Error(w, fmt.Sprintf("Failed to marshal Car: %v", err), http.StatusInternalServerError)        log.Printf("Error marshaling Car: %v", err)        return    }    // 设置Content-Type为application/x-protobuf,告知客户端数据类型    w.Header().Set("Content-Type", "application/x-protobuf")    // 写入二进制数据到HTTP响应    _, err = w.Write(binaryData)    if err != nil {        log.Printf("Error writing response: %v", err)    }    log.Println("Car object sent successfully.")}

注意:google.golang.org/protobuf/proto是Go Protobuf库的最新路径。如果您的项目使用的是旧版本(如github.com/golang/protobuf/proto),请相应调整导入路径。此外,导入”./car”需要根据您的car.pb.go文件实际存放的包路径进行调整。

Dart前端数据反序列化

在Dart前端,我们将使用HttpRequest发起AJAX请求获取Go后端发送的二进制数据,然后将其反序列化为Dart Car对象。

// main.dart (或者您的Dart应用程序的任何文件)import 'dart:html';import 'dart:typed_data';import 'car.pb.dart'; // 导入生成的 car.pb.dart 文件void main() {  // 可以在某个按钮点击事件或页面加载时调用此函数  getProtoBuffer();}void getProtoBuffer() {  HttpRequest.request(    "http://localhost:8080/getCarProto", // 确保URL与Go后端匹配    responseType: "arraybuffer", // 请求响应类型为ArrayBuffer  ).then((HttpRequest request) {    if (request.status == 200) {      // 获取响应的ArrayBuffer      ByteBuffer buffer = request.response as ByteBuffer;      // 将ByteBuffer转换为Uint8List,以便Protobuf库处理      // 这里的 Uint8List.view 是一个常见的转换方式,尤其是在旧版Dart或特定编译环境下      Uint8List uint8List = Uint8List.view(buffer, 0, buffer.lengthInBytes);       // 使用生成的Car类的fromBuffer方法反序列化数据      Car c = Car.fromBuffer(uint8List);      print("Received Car object:");      print("Make: ${c.make}");      print("NumDoors: ${c.numdoors}");    } else {      print("Error fetching protobuf data: ${request.statusText}");    }  }).catchError((error) {    print("Request failed with error: $error");  });}

重要提示:

CORS (跨域资源共享):如果您的Dart应用和Go后端运行在不同的端口或域名,浏览器会阻止跨域请求。您需要在Go后端配置CORS头,例如:

func handleGetCarProto(w http.ResponseWriter, r *http.Request) {    w.Header().Set("Access-Control-Allow-Origin", "*") // 允许所有来源,生产环境请指定具体域名    w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")    if r.Method == "OPTIONS" {        w.WriteHeader(http.StatusOK)        return    }    // ... 原有的序列化和发送逻辑}

Uint8List.view(buffer, 0, buffer.lengthInBytes):这个操作将ByteBuffer视图化为Uint8List,而不会进行数据拷贝,效率较高。在某些Dart版本或dart2js编译环境下,这可能是处理arraybuffer响应的推荐方式。

注意事项与最佳实践

错误处理:在Go和Dart代码中都应包含健壮的错误处理机制,例如检查proto.Marshal和HttpRequest.request的错误。Schema演进:当数据结构需要修改时(例如添加新字段),请遵循Protobuf的兼容性规则。不要改变现有字段的字段编号。不要改变现有字段的类型。删除字段时,不要重用其字段编号。添加新字段时,使用新的字段编号。将required字段改为optional字段是兼容的,反之则不兼容。HTTP Content-Type:在Go后端设置Content-Type: application/x-protobuf是一个良好的实践,它告知客户端响应体是Protobuf二进制数据。性能考虑:Protobuf在序列化和反序列化效率上通常优于JSON和XML,尤其是在数据量较大或对性能有严格要求的场景。安全性:传输Protobuf数据时,如果涉及敏感信息,应始终使用HTTPS加密传输。

总结

通过本教程,您已经掌握了如何利用Protocol Buffers在Go后端序列化数据,并通过HTTP AJAX请求将其传输到Dart前端进行反序列化的完整流程。这套方案提供了一种高效、跨语言且易于维护的数据交换机制,适用于构建高性能的分布式系统或Web应用程序。遵循Protobuf的设计原则和最佳实践,将有助于您构建稳定且可扩展的应用。

以上就是基于Protocol Buffers实现Go后端与Dart前端的数据交互的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1419464.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月16日 13:11:30
下一篇 2025年12月16日 13:11:48

相关推荐

  • HTML、CSS 和 JavaScript 中的简单侧边栏菜单

    构建一个简单的侧边栏菜单是一个很好的主意,它可以为您的网站添加有价值的功能和令人惊叹的外观。 侧边栏菜单对于客户找到不同项目的方式很有用,而不会让他们觉得自己有太多选择,从而创造了简单性和秩序。 今天,我将分享一个简单的 HTML、CSS 和 JavaScript 源代码来创建一个简单的侧边栏菜单。…

    2025年12月24日
    200
  • 前端代码辅助工具:如何选择最可靠的AI工具?

    前端代码辅助工具:可靠性探讨 对于前端工程师来说,在HTML、CSS和JavaScript开发中借助AI工具是司空见惯的事情。然而,并非所有工具都能提供同等的可靠性。 个性化需求 关于哪个AI工具最可靠,这个问题没有一刀切的答案。每个人的使用习惯和项目需求各不相同。以下是一些影响选择的重要因素: 立…

    2025年12月24日
    300
  • 带有 HTML、CSS 和 JavaScript 工具提示的响应式侧边导航栏

    响应式侧边导航栏不仅有助于改善网站的导航,还可以解决整齐放置链接的问题,从而增强用户体验。通过使用工具提示,可以让用户了解每个链接的功能,包括设计紧凑的情况。 在本教程中,我将解释使用 html、css、javascript 创建带有工具提示的响应式侧栏导航的完整代码。 对于那些一直想要一个干净、简…

    2025年12月24日
    000
  • 布局 – CSS 挑战

    您可以在 github 仓库中找到这篇文章中的所有代码。 您可以在这里查看视觉效果: 固定导航 – 布局 – codesandbox两列 – 布局 – codesandbox三列 – 布局 – codesandbox圣杯 &#8…

    2025年12月24日
    000
  • 隐藏元素 – CSS 挑战

    您可以在 github 仓库中找到这篇文章中的所有代码。 您可以在此处查看隐藏元素的视觉效果 – codesandbox 隐藏元素 hiding elements hiding elements hiding elements hiding elements hiding element…

    2025年12月24日
    400
  • 居中 – CSS 挑战

    您可以在 github 仓库中找到这篇文章中的所有代码。 您可以在此处查看垂直中心 – codesandbox 和水平中心的视觉效果。 通过 css 居中 垂直居中 centering centering centering centering centering centering立即…

    2025年12月24日 好文分享
    300
  • 如何在 Laravel 框架中轻松集成微信支付和支付宝支付?

    如何用 laravel 框架集成微信支付和支付宝支付 问题:如何在 laravel 框架中集成微信支付和支付宝支付? 回答: 建议使用 easywechat 的 laravel 版,easywechat 是一个由腾讯工程师开发的高质量微信开放平台 sdk,已被广泛地应用于许多 laravel 项目中…

    2025年12月24日
    000
  • 如何在移动端实现子 div 在父 div 内任意滑动查看?

    如何在移动端中实现让子 div 在父 div 内任意滑动查看 在移动端开发中,有时我们需要让子 div 在父 div 内任意滑动查看。然而,使用滚动条无法实现负值移动,因此需要采用其他方法。 解决方案: 使用绝对布局(absolute)或相对布局(relative):将子 div 设置为绝对或相对定…

    2025年12月24日
    000
  • 移动端嵌套 DIV 中子 DIV 如何水平滑动?

    移动端嵌套 DIV 中子 DIV 滑动 在移动端开发中,遇到这样的问题:当子 DIV 的高度小于父 DIV 时,无法在父 DIV 中水平滚动子 DIV。 无限画布 要实现子 DIV 在父 DIV 中任意滑动,需要创建一个无限画布。使用滚动无法达到负值,因此需要使用其他方法。 相对定位 一种方法是将子…

    2025年12月24日
    000
  • 移动端项目中,如何消除rem字体大小计算带来的CSS扭曲?

    移动端项目中消除rem字体大小计算带来的css扭曲 在移动端项目中,使用rem计算根节点字体大小可以实现自适应布局。但是,此方法可能会导致页面打开时出现css扭曲,这是因为页面内容在根节点字体大小赋值后重新渲染造成的。 解决方案: 要避免这种情况,将计算根节点字体大小的js脚本移动到页面的最前面,即…

    2025年12月24日
    000
  • Nuxt 移动端项目中 rem 计算导致 CSS 变形,如何解决?

    Nuxt 移动端项目中解决 rem 计算导致 CSS 变形 在 Nuxt 移动端项目中使用 rem 计算根节点字体大小时,可能会遇到一个问题:页面内容在字体大小发生变化时会重绘,导致 CSS 变形。 解决方案: 可将计算根节点字体大小的 JS 代码块置于页面最前端的 标签内,确保在其他资源加载之前执…

    2025年12月24日
    200
  • Nuxt 移动端项目使用 rem 计算字体大小导致页面变形,如何解决?

    rem 计算导致移动端页面变形的解决方法 在 nuxt 移动端项目中使用 rem 计算根节点字体大小时,页面会发生内容重绘,导致页面打开时出现样式变形。如何避免这种现象? 解决方案: 移动根节点字体大小计算代码到页面顶部,即 head 中。 原理: flexível.js 也遇到了类似问题,它的解决…

    2025年12月24日
    000
  • 形状 – CSS 挑战

    您可以在 github 仓库中找到这篇文章中的所有代码。 您可以在此处查看 codesandbox 的视觉效果。 通过css绘制各种形状 如何在 css 中绘制正方形、梯形、三角形、异形三角形、扇形、圆形、半圆、固定宽高比、0.5px 线? shapes 0.5px line .square { w…

    2025年12月24日
    000
  • 有哪些美观的开源数字大屏驾驶舱框架?

    开源数字大屏驾驶舱框架推荐 问题:有哪些美观的开源数字大屏驾驶舱框架? 答案: 资源包 [弗若恩智能大屏驾驶舱开发资源包](https://www.fanruan.com/resource/152) 软件 [弗若恩报表 – 数字大屏可视化组件](https://www.fanruan.c…

    2025年12月24日
    000
  • 网站底部如何实现飘彩带效果?

    网站底部飘彩带效果的 js 库实现 许多网站都会在特殊节日或活动中添加一些趣味性的视觉效果,例如点击按钮后散发的五彩缤纷的彩带。对于一个特定的网站来说,其飘彩带效果的实现方式可能有以下几个方面: 以 https://dub.sh/ 网站为例,它底部按钮点击后的彩带效果是由 javascript 库实…

    2025年12月24日
    000
  • 网站彩带效果背后是哪个JS库?

    网站彩带效果背后是哪个js库? 当你访问某些网站时,点击按钮后,屏幕上会飘出五颜六色的彩带,营造出庆祝的氛围。这些效果是通过使用javascript库实现的。 问题: 哪个javascript库能够实现网站上点击按钮散发彩带的效果? 答案: 根据给定网站的源代码分析: 可以发现,该网站使用了以下js…

    好文分享 2025年12月24日
    100
  • 产品预览卡项目

    这个项目最初是来自 Frontend Mentor 的挑战,旨在使用 HTML 和 CSS 创建响应式产品预览卡。最初的任务是设计一张具有视觉吸引力和功能性的产品卡,能够无缝适应各种屏幕尺寸。这涉及使用 CSS 媒体查询来确保布局在不同设备上保持一致且用户友好。产品卡包含产品图像、标签、标题、描述和…

    2025年12月24日
    100
  • 如何利用 echarts-gl 绘制带发光的 3D 图表?

    如何绘制带发光的 3d 图表,类似于 echarts 中的示例? 为了实现类似的 3d 图表效果,需要引入 echarts-gl 库:https://github.com/ecomfe/echarts-gl。 echarts-gl 专用于在 webgl 环境中渲染 3d 图形。它提供了各种 3d 图…

    2025年12月24日
    000
  • 如何在 Element UI 的 el-rate 组件中实现 5 颗星 5 分制与百分制之间的转换?

    如何在el-rate中将5颗星5分制的分值显示为5颗星百分制? 要实现该效果,只需使用 el-rate 组件的 allow-half 属性。在设置 allow-half 属性后,获得的结果乘以 20 即可得到0-100之间的百分制分数。如下所示: score = score * 20; 动态显示鼠标…

    2025年12月24日
    100
  • Bear 博客上的浅色/深色模式分步指南

    我最近使用偏好颜色方案媒体功能与 light-dark() 颜色函数相结合,在我的 bear 博客上实现了亮/暗模式切换。 我是这样做的。 第 1 步:设置 css css 在过去几年中获得了一些很酷的新功能,包括 light-dark() 颜色函数。此功能可让您为任何元素指定两种颜色 &#8211…

    2025年12月24日
    100

发表回复

登录后才能评论
关注微信