Go WSDL

最近在实现一个功能时需要使用第三方的接口,由于第三方只提供了一个 WSDL 文件的链接,于是研究了 golang 如何解析 WSDL 并调用相应接口, 本文就是介绍 WSDL 和 go 如何解析并调用。 WSDL 介绍 WSDL 是 Web Services Description Language(Web服务描述语言)的缩写。它是一种用于描述基于Web服务的通信协议和消息格式的XML格式语言。 WSDL 被广泛用于描述Web服务的接口和操作。它定义了Web服务所提供的功能、方法、参数、数据类型以及与服务进行交互的方式。通过WSDL文件,客户端应用程序可以了解如何与特定的Web服务进行通信。 WSDL文件通常包含以下几个主要部分: 服务定义:描述了Web服务的名称、命名空间和位置。 类型定义:定义了Web服务中使用的数据类型,例如字符串、整数等。 消息定义:定义了Web服务中使用的消息格式,包括输入和输出消息。 操作定义:定义了Web服务的操作或方法,包括输入和输出消息以及相关的参数。 绑定定义:定义了Web服务使用的通信协议和消息格式,例如SOAP(Simple Object Access Protocol)和HTTP(Hypertext Transfer Protocol)。 服务定义:将服务、绑定和端口等部分组合在一起,定义了Web服务的完整描述。 使用WSDL,开发人员可以生成客户端代码,使其能够与Web服务进行交互。客户端可以根据WSDL文件了解Web服务的结构和可用方法,以便正确地构造请求和解析响应。 总之,WSDL是一种用于描述Web服务接口和操作的语言,它提供了一种标准化的方式来描述和访问Web服务。 gowsdl go语言如何解析 wsdl呢,我们使用 gowsdl 来解析 wsdl ,生成相应的 golang 代码。 安装 go install github.com/hooklift/gowsdl/cmd/gowsdl@latest 生成代码 使用命令 gowsdl -o myservice.go http://www.example.com/myservice?wsdl 生成代码。如果网络情况不好,我们也可以将 WSDL 文件下载下来解析 gowsdl -o xx.go a.xml。 解析完毕会生成相应的客户端文件,我们只要通过生成的客户端链接服务即可执行相应的方法。 code: package main import ( "adx/myservice" "fmt" "github.com/hooklift/gowsdl/soap" "golang.org/x/oauth2" "log" ) func main() { client := soap.NewClient("https://ads.xxx?wsdl", soap.WithHTTPHeaders(map[string]string{ "Authorization": fmt.Sprintf("Bearer %s", xxxx), })) service := myservice.NewxxServiceInterface(client) ReportableType := myservice.xx type_ := myservice.xx reply, err := service.xx(&myservice.xx{ Keys: []*myservice.xx{{ Name: "test111", DisplayName: "test111", Type_: &type_, ReportableType: &ReportableType, }}, }) if err != nil { log.Fatal(err) return } log.Println(reply) } 小结 在对 soap 库的简单尝试后,发现了一些问题: ...

九月 23, 2023 · overstarry

playwright-go浏览器截图

以前的文章介绍了 chromedp 进行浏览器网页截图, 这次介绍一种新的网页截图的方法——即使用 playwright 进行浏览器网页截图。 playwright 介绍 Playwright是一个用于自动化浏览器操作的开源工具集。它由微软开发并于2020年发布,旨在提供一种跨浏览器、跨平台的解决方案,可用于测试Web应用程序、编写爬虫、执行自动化任务等。 Playwright支持多种主流浏览器,包括Chrome、Firefox、Safari和Edge,它提供了一组简单易用的API,可以模拟用户与Web页面的交互行为,例如点击、填写表单、导航等。与其他类似工具相比,Playwright的一个重要特点是它的跨浏览器支持,这意味着你可以使用相同的代码在不同浏览器上运行你的自动化任务,而不需要为每个浏览器单独编写代码。 Playwright还提供了强大的调试功能,可以帮助开发人员在自动化过程中定位和解决问题。它支持截图和录制操作,使得调试变得更加直观和高效。 另外,Playwright还具有一些高级功能,例如可以模拟不同的设备、网络环境和地理位置,以及支持并发执行多个浏览器实例等,这些功能使得它在编写复杂的自动化任务时非常有用。 由于我日常主要使用 go 语言进行开发,所以本文的内容主要以 playwright 的 go 模块 playwright-go 为主要介绍。 安装 go get -u github.com/playwright-community/playwright-go 安装相关浏览器和操作系统依赖项: go run github.com/playwright-community/playwright-go/cmd/playwright@latest install --with-deps # Or go install github.com/playwright-community/playwright-go/cmd/playwright@latest playwright install --with-deps 也可以在代码中使用以下代码安装: err := playwright.Install() 通过安装截图可以看出安装了3大主流浏览器和ffmpeg。 例子 接下来我们看一个官方的例子,从Hacker News中抓取当前投票最高的项目。 package main import ( "fmt" "log" "github.com/playwright-community/playwright-go" ) func main() { pw, err := playwright.Run() if err != nil { log.Fatalf("could not start playwright: %v", err) } browser, err := pw.Chromium.Launch() if err != nil { log.Fatalf("could not launch browser: %v", err) } page, err := browser.NewPage() if err != nil { log.Fatalf("could not create page: %v", err) } if _, err = page.Goto("https://news.ycombinator.com"); err != nil { log.Fatalf("could not goto: %v", err) } entries, err := page.Locator(".athing").All() if err != nil { log.Fatalf("could not get entries: %v", err) } for i, entry := range entries { title, err := entry.Locator("td.title > span > a").TextContent() if err != nil { log.Fatalf("could not get text content: %v", err) } fmt.Printf("%d: %s\n", i+1, title) } if err = browser.Close(); err != nil { log.Fatalf("could not close browser: %v", err) } if err = pw.Stop(); err != nil { log.Fatalf("could not stop Playwright: %v", err) } } ...

九月 2, 2023 · overstarry

gonew介绍

前几周。在关注的go提案每周会议中,发现了一条比较感兴趣的内容: gonew: templates for new modules ,通过标题可以猜到 gonew 应该是一个通过配置项目模板生成新项目的模块。 通过对 discussions 中 rsc 所描述的内容进行分析,可以得知为什么要启动这么一个新项目: go团队经常收到用户的请求,想要通过模板启动一个新项目,即以某种基本的项目模板来创建一个新Go module。Russ私下编写了一个实现这个功能的小工具:rsc.io/tmp/gonew. Russ在google内部宣传该工具后,Google内部的一些团队便定制了一些模板(template) ,尤其是ServiceWeaver团队的响应尤为积极。这一切最终让Russ决定引入golang.org/x/tools/cmd/gonew。 gonew工具的引入大幅简化了Go项目的创建,同时由于对自定义项目模板的支持,也可以提高Go项目的标准化水平。目前 gonew 工具是实验性的,后续可能会增加新的特性,但目前的核心功能是会保留的。 通过对 discussions 中社区用户开发着的回应可以看出,大家纷纷讲述了没有 gonew 前所使用的工具,并对 gonew 建言献策,可以看出大部分的开发者都十分欢迎这个新功能的。 接下来就由我来介绍 gonew 。 安装 通过以下命令安装 gonew: go install golang.org/x/tools/cmd/gonew@latest $ go install golang.org/x/tools/cmd/gonew@latest go: downloading golang.org/x/tools v0.12.0 go: downloading golang.org/x/mod v0.12.0 执行 gonew: $ gonew usage: gonew srcmod[@version] [dstmod [dir]] See https://pkg.go.dev/golang.org/x/tools/cmd/gonew. 接下来我来介绍 gonew 的几种用法。 使用 用法1 用法1是基于模板创建同名项目,我们以 https://github.com/minio/mc 这个项目为例子。 执行 gonew github.com/minio/mc ...

八月 19, 2023 · overstarry

ent相同列名排序问题解决

前言 最近在开发的时候,需要进行数据库计算,主要是根据表中的某些字段进行汇总计算,但由于数据库表中已有同名字段名,ent 不会使用计算后的指标,默认使用schema中定义的字段,导致无法返回正确的结果。 针对这种情况,我能想到的方法有2种: 1) 不使用同名的字段名 2) 查找ent是否有相关的解决方案。 这里我采用了第二种方法,查找相关的issues, 通过查找相关issue,找到了相关的解决方案: ent 的 sql/modifier 特性。 场景重现 定义一个新的数据库表结构,结构如下: func (Ad) Fields() []ent.Field { return []ent.Field{ field.Float("estimated_earnings"), field.Int("page_views"), field.Time("date"), field.Float("page_views_rpm").Optional(), } } page_views_rpm 字段是由 estimated_earnings 和 page_views 计算而来。 编写相应的查询代码: package main import ( "context" "entgo.io/ent/dialect/sql" "fmt" _ "github.com/lib/pq" "log" "modifier-demo/ent" "modifier-demo/ent/ad" "time" ) type Ads struct { EstimatedEarnings float64 `json:"estimated_earnings"` PageViews int64 `json:"page_views"` Date time.Time `json:"date"` PageViewsRpm float64 `json:"page_views_rpm"` } func main() { client, err := ent.Open("postgres", "host=127.0.0.1 port=5432 sslmode=disable user=postgres dbname=data_test password=mysecretpassword") if err != nil { log.Fatalf("failed opening connection to postgres: %v", err) } defer client.Close() // Run the auto migration tool. if err := client.Schema.Create(context.Background()); err != nil { log.Fatalf("failed creating schema resources: %v", err) } var a []Ads err = client.Debug().Ad.Query().Order(ent.Desc(ad.FieldPageViewsRpm)).GroupBy(ad.FieldDate).Aggregate(func(selector *sql.Selector) string { return sql.As(" CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views)*1.0, 0.0)*1000, 0)AS numeric(10,2))", "page_views_rpm") }).Scan(context.TODO(), &a) if err != nil { return } fmt.Println(a) } 主要是根据date来汇总并重新计算 page_views_rpm 字段,运行代码后发现没有成功输出,打印后发现ent使用了旧的PageViewsRpm字段进行排序,导致sql无法顺利运行。 ...

八月 12, 2023 · overstarry

Golang_embed简单介绍

最近需要使用 golang1.16 中的功能 embed ,本文简单记录下 embed 的使用。 embed 介绍 Go 1.16 引入了embed包,允许我们在编译时将静态文件(例如 .go、.html、.css、.js 等)嵌入到 Go 源文件中。这在构建静态网站、单页应用程序(SPA)和其他项目时非常有用。 主要有几个优点: 方便部署:不需要再部署静态资源文件,所有的资源都直接嵌入到可执行文件中。 安全:用户无法直接访问或修改嵌入的文件。 版本管理:和Go代码一起版本控制。 使用 嵌入为字符串 可以将文件内容保存到字符串变量中。 package main import ( _ "embed" "fmt" ) //go:embed hello.txt var s string func main() { fmt.Println(s) } 文件路径下有个 hello.txt,内容如下:hello, overstarry,代码运行输出:hello, overstarry 保存为 []bytes 还可以将文件内容保存为 []bytes变量 package main import ( _ "embed" "fmt" ) //go:embed hello.txt var s []byte func main() { fmt.Println(string(s)) } 运行代码输出内容与上面一致。 保存为 fs.FS 类型 还可以将文件保存为 fs.FS 类型,这在嵌入多个文件时非常有用(string和[]bytes不支持多个//go:embed指令)。 ...

八月 5, 2023 · overstarry