首页 > 其他分享 >Go Web项目分层 对比看下portal server 转载

Go Web项目分层 对比看下portal server 转载

时间:2024-01-18 19:35:01浏览次数:16  
标签:Web HTTP required server json portal int64 结构 thrift

这样我们 Controller 中的入口函数就变成了下面这样:

func CreateOrder(ctx context.Context, req *CreateOrderStruct) (
    *CreateOrderRespStruct, error,
) {
    // ...
}

CreateOrder 有两个参数,ctx 用来传入 trace_id 一类的需要串联请求的全局参数,req 里存储了我们创建订单所需要的所有输入信息。返回结果是一个响应结构体和错误。可以认为,我们的代码运行到 Controller 层之后,就没有任何与“协议”相关的代码了。在这里你找不到 http.Request ,也找不到 http.ResponseWriter,也找不到任何与 thrift 或者 gRPC 相关的字眼。

在协议 (Protocol) 层,处理 http 协议的大概代码如下:

// 在协议层中定义
type CreateOrderRequest struct {   
OrderID int64 `json:"order_id"`   
// ...}
// 在控制器中定义
type CreateOrderParams struct {    
OrderID int64
}
func HTTPCreateOrderHandler(wr http.ResponseWriter, r *http.Request) 
{   
var req CreateOrderRequest   
var params CreateOrderParams   
ctx := context.TODO()    
// 将数据绑定到 req   
bind(r, &req)    
// 绑定到独立于协议的映射协议  
map(req, params)    
logicResp,err := controller.CreateOrder(ctx, &params)  
if err != nil {}   
// ...}

理论上我们可以用同一个请求结构体组合上不同的 tag,来达到一个结构体来给不同的协议复用的目的。不过遗憾的是在 thrift 中,请求结构体也是通过 IDL 生成的,其内容在自动生成的 ttypes.go 文件中,我们还是需要在 thrift 的入口将这个自动生成的结构体映射到我们 logic 入口所需要的结构体上。gRPC 也是类似。这部分代码还是需要的。

大家可能已经可以看出来了,协议细节处理这一层实际上有大量重复劳动,每一个接口在协议这一层的处理,无非是把数据从协议特定的结构体(例如 http.Request,thrift 的被包装过了)读出来,再绑定到我们协议无关的结构体上,再把这个结构体映射到 Controller 入口的结构体上,这些代码实际上长得都差不多。

差不多的代码都遵循着某种模式,那么我们可以对这些模式进行简单的抽象,用代码生成的方式,把繁复的协议处理代码从工作内容中抽离出去。

先来看看 HTTP 对应的结构体、thrift 对应的结构体和我们协议无关的结构体分别长什么样子:

// http 请求结构体type CreateOrder struct {  
OrderID    int64   `json:"order_id" validate:"required"`   
UserID     int64   `json:"user_id" validate:"required"`   
ProductID  int     `json:"prod_id" validate:"required"`   
Addr       string  `json:"addr" validate:"required"`
}
// thrift 请求结构体type FeatureSetParams struct {    
DriverID   int64  `thrift:"driverID,1,required"`    
OrderID    int64  `thrift:"OrderID,2,required"`    
UserID     int64  `thrift:"UserID,3,required"`    
ProductID  int    `thrift:"ProductID,4,required"`    
Addr       string `thrift:"Addr,5,required"`
}
// controller input structtype CreateOrderParams struct {  
OrderID   int64   
UserID    int64   
ProductID int   
Addr      string}

我们需要通过一个源结构体来生成我们需要的 HTTP 和 thrift 入口代码。再观察一下上面定义的三种结构体,实际上我们只要能用一个结构体生成 thrift 的 IDL,以及 HTTP 服务的“IDL(实际上就是带 json 或 form 相关 tag 的结构体定义)”就可以了。这个初始的结构体我们可以把结构体上的 HTTP 的 tag 和 thrift 的 tag 揉在一起:

type FeatureSetParams struct {    
    DriverID    int64  `thrift:"driverID,1,required" json:"driver_id"`   
    OrderID     int64  `thrift:"OrderID,2,required" json:"order_id"`  
    UserID      int64  `thrift:"UserID,3,required" json:"user_id"`   
    ProductID   int    `thrift:"ProductID,4,required" json:"prod_id"`  
    Addr        string `thrift:"Addr,5,required" json:"addr"`}

然后通过代码生成把 thrift 的 IDL 和 HTTP 的请求结构体都生成出来,如下图所示

至于用什么手段来生成,可以通过 Go语言内置的 Parser 读取文本文件中的 Go 源代码,然后根据 AST 来生成目标代码,也可以简单地把这个源结构体和 Generator 的代码放在一起编译,让结构体作为 Generator 的输入参数(这样会更简单一些),都是可以的。

当然这种思路并不是唯一选择,我们还可以通过解析 thrift 的 IDL,生成一套 HTTP 接口的结构体。如果你选择这么做,那整个流程就变成了下图所示。

也可以从 thrift 生成其它部分
图:也可以从 thrift 生成其它部分

看起来比之前的图顺畅一点,不过如果选择了这么做,就需要自行对 thrift 的 IDL 进行解析,也就是相当于可能要手写一个 thrift 的 IDL 的 Parser,虽然现在有 Antlr 或者 peg 能帮你简化这些 Parser 的书写工作,但在“解析”的这一步我们不希望引入太多的工作量,所以量力而行即可。

既然工作流已经成型,我们可以琢磨一下怎么让整个流程对用户更加友好。比如在前面的生成环境引入 Web 页面,只要让用户点点鼠标就能生成 SDK,这些就靠大家自己去探索了。

虽然我们成功地使自己的项目在入口支持了多种交互协议,但是还有一些问题没有解决。本节中所叙述的分层没有将中间件作为项目的分层考虑进去。如果我们考虑中间件的话,请求的流程是什么样的?见下图所示。

加入中间件后的控制流
图:加入中间件后的控制流

之前我们学习的中间件是和 HTTP 协议强相关的,遗憾的是在 thrift 中看起来没有和 HTTP 中对等的解决这些非功能性逻辑代码重复问题的中间件。所以我们在图上写 thrift stuff 。这些 stuff 可能需要你手写去实现,然后每次增加一个新的 thrift 接口,就需要去写一遍这些非功能性代码。

这也是很多企业项目所面临的真实问题,遗憾的是开源界并没有这样方便的多协议中间件解决方案。当然了,前面我们也说过,很多时候我们给自己保留的 HTTP 接口只是用来做调试,并不会暴露给外人用。这种情况下,这些非功能性的代码只要在 thrift 的代码中完成即可。

 

标签:Web,HTTP,required,server,json,portal,int64,结构,thrift
From: https://www.cnblogs.com/codestack/p/17973233

相关文章

  • jmeter使用jdbc连接SQL server,执行SQL报错处理
    前置环境参数:jdk-8u391-windows-x64,驱动:sqljdbc4.jar备注:这是解决后的截图,将就用问题一:使用jmeter5.5,使用jdbc连接SQLserver,执行SQL报错处理,如下图 报错信息:java.lang.UnsupportedClassVersionError:com/microsoft/sqlserver/jdbc/SQLServerDriverhasbeencompiledby......
  • 使用jmeter对websockt和protobuf进行压力测试
     这是基于JmeterWebsocketSampler的插件,支持对基于websocket和protobuf的服务器进行测试。 想要应用到具体业务中,还需要进行代码改造,可参考demo代码。 工程结构 两个子工程组成: 1. jmeter-websocketprotobuf-front工程。基于maciejzaleski/JMeter-WebSocketSampler(htt......
  • NSS Round#16 web
    RCE但是没有完全RCE<?phperror_reporting(0);highlight_file(__file__);include('level2.php');if(isset($_GET['md5_1'])&&isset($_GET['md5_2'])){if((string)$_GET['md5_1']!==(string)$_GET['md5_2&......
  • Web前端新手入门系列:案例1 招商银行页面的制作
    一次比较复杂的网页设计(对初学者而言)效果图代码可能不太符合规范,但效果差不多(HTML部分<!DOCTYPEhtml><htmllang="en"xmlns="http://www.w3.org/1999/xhtml"><head><metacharset="utf-8"/><title>招商银行</title>&......
  • C# WebApi传参及Postman调试
    概述欢迎来到本文,本篇文章将会探讨C#WebApi中传递参数的方法。在WebApi中,参数传递是一个非常重要的概念,因为它使得我们能够从客户端获取数据,并将数据传递到服务器端进行处理。WebApi是一种使用HTTP协议进行通信的RESTful服务,它可以通过各种方式传递参数。在本文中,我们只会针对Ge......
  • 【SCTF-Round#16】 Web和Crypto详细完整WP
    每天都要加油哦!   ------2024-01-18 11:16:55[NSSRound#16Basic]RCE但是没有完全RCE<?phperror_reporting(0);highlight_file(__file__);include('level2.php');if (isset($_GET['md5_1']) && isset($_GET['md5_2'])) {    if ((str......
  • Web Components从技术解析到生态应用个人心得指北
    WebComponents浅析WebComponents是一种使用封装的、可重用的HTML标签、样式和行为来创建自定义元素的Web技术。WebComponents自己本身不是一个规范,而是一套整体技术,包含下面3个独立规范:CustomElements:允许开发者定义自己的HTML标签(考虑SEO,还是语义化为好)。Sha......
  • .NET Core如何调SAP接口-.NET Core如何调WebService接口
     情况说明 客户提供一个SAP接口,接口通过浏览器可以打开查看,如下图: 输入帐号密码后登录: 接口开发连接接口服务上述情况,SAP接口已就绪,现在开始开发接口调用。首先,创建.NETCoreWeb项目,然后如下图,连接接口服务。           创......
  • 探索Web开发的未来——使用KendoReact服务器组件
    KendoUI是带有jQuery、Angular、React和Vue库的JavaScriptUI组件的最终集合,无论选择哪种JavaScript框架,都可以快速构建高性能响应式Web应用程序。通过可自定义的UI组件,KendoUI可以创建数据丰富的桌面、平板和移动Web应用程序。通过响应式的布局、强大的数据绑定、跨浏览器兼容......
  • webpack部分
    1.安装jquerynpminstalljquery-S2.引入到index.jsimport$from'jquery$(function(){})2.webpack的使用[email protected]@4.7.2-D2.1webpack.config.js配置在根目录下创建webpack.config.jsconstpath=requirt('path')module......