Moov的使命是 为开发者提供一种简单的方式来创建和集成银行处理到他们自己的软件产品中。我们的开源项目每一个都专注于解决金融服务中的单一职责,并围绕着性能、可扩展性和易用性进行设计。
ISO8583 在 Go 中实现了 ISO 8583 消息读取和写入。ISO 8583 是一种用于银行卡交易消息的国际标准,它定义了消息格式和通信流程。它被全球主要的银行卡网络(如Visa、Mastercard和Verve)所使用。该标准支持银行卡购买、取款、存款、退款、冲正、余额查询、账户之间转账、管理消息、安全密钥交换等各种交易。
Moov ISO8583 是一个 Go 包,经过了 彻底的现实世界测试和信任。该项目在真实世界的高风险场景中已经证明了其可靠性和健壮性。如果您发现任何缺失的功能/错误/文档不清晰,请通过 提交 issue 告知我们。谢谢!
本项目使用 Go Modules。请参考 Golang 的安装 说明 来设置 Go 环境。您可以下载源代码,我们也提供了 已标记和发布的版本。我们强烈建议您在生产环境中使用已发布的标记版本。
尽管我们努力拥抱最新的语言增强功能,但我们也理解需要一定程度的向后兼容性。我们知道并非所有人都可以立即升级到最新版本。我们的理念是向前发展,拥抱新事物,但不会让任何人立即落下。
截至目前,我们正在支持以下版本,如 setup-go action step 所引用:
stable
(指向当前 Go 版本)oldstable
(指向上一个 Go 版本)setup-go action 自动管理版本控制,使我们能够始终与最新和前一个 Go 版本保持一致。
每当 Go 的新版本发布时,我们都会更新我们的系统,并确保我们的项目完全兼容。与此同时,我们将继续支持前一个版本。但是,一旦新版本发布,"前前一个"版本将不再受官方支持。
为了确保我们对这些版本的支持承诺,我们已经配置了 GitHub CI 操作,使用当前版本和前一版本的 Go 来测试我们的代码。这意味着,如果您正在使用这两个版本中的任何一个,您都可以放心地使用该项目。
go get github.com/moov-io/iso8583
目前,我们已经定义了以下 ISO 8583 规范:
Spec87ASCII 适用于大多数用例。只需使用 specs.Spec87ASCII
实例化一个新消息:
isomessage := iso8583.NewMessage(specs.Spec87ASCII)
如果此规范不满足您的需求,我们鼓励您修改它或使用以下信息创建自己的规范。 首先,您需要定义在ISO8583规范中描述的消息字段的格式。每个数据字段都有一种类型及其自身的规范。您可以创建一个"NewBitmap"、"NewString"或"NewNumeric"字段。每个单独的字段规范由几个元素组成:
元素 | 注释 | 示例 |
---|---|---|
长度 | 最大字段长度(字节、字符或数字),对于定长和变长都适用。 | 10 |
描述 | 描述数据字段的内容。 | "主账号" |
编码 | 设置编码类型(ASCII , Hex , Binary , BCD , LBCD , EBCDIC )。 | encoding.ASCII |
前缀 | 设置字段长度和类型的编码(ASCII , Hex , Binary , BCD , EBCDIC )为定长或变长(Fixed , L , LL , LLL , LLLL )。'L'的数量对应于变长中的数字位数。 | prefix.ASCII.Fixed |
填充 (可选) | 设置填充方向和类型。 | padding.Left('0') |
某些ISO8583规范可能没有0号和1号字段,但我们会使用它们来表示MTI和Bitmap。因为从技术上讲,它们只是普通的字段。我们也使用字段规范来描述MTI和Bitmap。我们目前使用String
字段来表示MTI,同时我们有一个单独的Bitmap
字段来表示位图。
以下示例创建了一个包含三个单独字段(不包括MTI和Bitmap)的完整规范:
spec := &iso8583.MessageSpec{ Fields: map[int]field.Field{ 0: field.NewString(&field.Spec{ Length: 4, Description: "消息类型标识符", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, }), 1: field.NewBitmap(&field.Spec{ Description: "位图", Enc: encoding.Hex, Pref: prefix.Hex.Fixed, }), // 消息字段: 2: field.NewString(&field.Spec{ Length: 19, Description: "主账号", Enc: encoding.ASCII, Pref: prefix.ASCII.LL, }), 3: field.NewNumeric(&field.Spec{ Length: 6, Description: "处理码", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 4: field.NewString(&field.Spec{ Length: 12, Description: "交易金额", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), }, }
以下示例创建了一个包含三个单独字段(不包括MTI和Bitmap)的完整规范。它与上面的示例不同,通过展示位图字段的可扩展性。这对于定义主位图和次位图的规范很有用。
spec := &iso8583.MessageSpec{ Fields: map[int]field.Field{ 0: field.NewString(&field.Spec{ Length: 4, Description: "消息类型标识符", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, }), 1: field.NewBitmap(&field.Spec{ Description: "位图", Enc: encoding.Hex, Pref: prefix.Hex.Fixed, }), // 消息字段: 2: field.NewString(&field.Spec{ Length: 19, Description: "主账号", Enc: encoding.ASCII, Pref: prefix.ASCII.LL, }), 3: field.NewNumeric(&field.Spec{ Length: 6, Description: "处理码", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 4: field.NewString(&field.Spec{ Length: 12, Description: "交易金额", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), // 从1993年的规范中提取 67: field.NewNumeric(&field.Spec{ Length: 2, Description: "扩展付款数据", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), }, }
定义了规范后,您可以构建一条消息。根据提供的规范,将消息的二进制表示打包,可以直接将其发送到支付系统!
请注意,在下面的示例中,您不需要手动设置位图值,因为它会在打包过程中自动生成。
如果您只需要设置几个字段,可以使用message.Field(id, string)
或message.BinaryField(id, []byte)
轻松设置,如下所示:
// 使用定义的规范创建消息 message := NewMessage(spec) // 在字段0设置消息类型标识符 message.MTI("0100") // 根据需要将所有消息字段设置为字符串 err := message.Field(2, "4242424242424242") // 处理错误 err = message.Field(3, "123456") // 处理错误 err = message.Field(4, "100") // 处理错误 // 生成消息的二进制表示rawMessage rawMessage, err := message.Pack() // 现在您可以通过网络发送rawMessage
使用单个字段的工作方式仅限于两种类型:string
或[]byte
。底层字段会将输入转换为自己的类型。如果失败,则会返回错误。
当您需要访问很多字段,并且想要使用字段类型工作时,使用带有message.Marshal(data)
的结构体会更加方便。
首先,您需要定义一个包含要设置的字段的结构体。字段应该对应于规范字段类型。以下是一个示例:
// 列出您想要设置的字段,使用`index`标签添加字段索引或标签(对于复合子字段) // 使用与消息规范相同的类型 type NetworkManagementRequest struct { MTI *field.String `index:"0"` TransmissionDateTime *field.String `index:"7"` STAN *field.String `index:"11"` InformationCode *field.String `index:"70"` } message := NewMessage(spec)
现在, 将有字段的数据传递到消息中 err := message.Marshal(&NetworkManagementRequest{ MTI: field.NewStringValue("0800"), TransmissionDateTime: field.NewStringValue(time.Now().UTC().Format("060102150405")), STAN: field.NewStringValue("000001"), InformationCode: field.NewStringValue("001"), })
// 对消息进行打包并发送给您的提供商 requestMessage, err := message.Pack()
当您有一个二进制(打包)消息并知道它遵循的规范时, 您可以解包它并访问数据。 再次, 您有两种数据访问选择: 访问单个字段或使用消息字段值填充结构体。
您可以使用message.GetString(id)
, message.GetBytes(id)
来访问单个字段的值, 如下所示:
message := NewMessage(spec) message.Unpack(rawMessage) mti, err := message.GetMTI() // MTI: 0100 // 处理错误 pan, err := message.GetString(2) // 卡号: 4242424242424242 // 处理错误 processingCode, err := message.GetString(3) // 处理码: 123456 // 处理错误 amount, err := message.GetString(4) // 交易金额: 100 // 处理错误
当您获取单个字段的值时, 您仍然限于string
或[]byte
类型。
要获取多个字段的值及其 类型, 只需将指向您想要的数据的结构体指针传递给message.Unmarshal(data)
即可, 如下所示:
// 列出您想要设置的字段, 添加带有字段索引或标签的`index`标签(对于复合子字段) // 使用与消息规范相同的类型 type NetworkManagementRequest struct { MTI *field.String `index:"0"` TransmissionDateTime *field.String `index:"7"` STAN *field.String `index:"11"` InformationCode *field.String `index:"70"` } message := NewMessage(spec) // 让我们解包二进制消息 err := message.Unpack(rawMessage) // 处理错误 // 创建指向空结构体的指针 data := &NetworkManagementRequest{} // 将字段值获取到数据结构中 err = message.Unmarshal(data) // 处理错误 // 现在你可以访问字段值 data.MTI.Value() // "0100" data.TransmissionDateTime.Value() // "220102103212" data.STAN.Value() // "000001" data.InformationCode.Value() // "001"
有关完整的代码示例, 请查看./message_test.go。
该软件包中有一个Describe
函数, 它以人类可读的方式显示所有消息字段。 以下是如何将消息字段及其值打印到标准输出的示例:
// 将消息打印到os.Stdout iso8583.Describe(message, os.Stdout)
它将产生以下输出:
MTI........................................: 0100
Bitmap.....................................: 000000000000000000000000000000000000000000000000
Bitmap bits................................: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
F000 Message Type Indicator................: 0100
F002 Primary Account Number................: 4242****4242
F003 Processing Code.......................: 123456
F004 Transaction Amount....................: 100
F020 PAN Extended Country Code.............: 4242****4242
F035 Track 2 Data..........................: 4000****0506=2512111123400001230
F036 Track 3 Data..........................: 011234****3445=724724000000000****00300XXXX020200099010=********************==1=100000000000000000**
F045 Track 1 Data..........................: B4815****1896^YATES/EUGENE L^^^356858 00998000000
F052 PIN Data..............................: 12****78
F055 ICC Data – EMV Having Multiple Tags...: ICC ... Tags
默认情况下, 我们应用iso8583.DefaultFilters
来掩盖具有敏感数据的字段的值。 您可以定义自己的过滤器函数并屏蔽特定字段, 如下所示:
filterAll = func(in string, data field.Field) string { runesInString := utf8.RuneCountInString(in) return strings.Repeat("*", runesInString) } // 仅过滤字段2的值 iso8583.Describe(message, os.Stdout, filterAll(2, filterAll)) // 输出: // F002 Primary Account Number................: ************
如果您想查看未过滤的值, 可以使用我们定义的无操作过滤器iso8583.DoNotFilterFields
:
// 显示未过滤的字段值 iso8583.Describe(message, os.Stdout, DoNotFilterFields()...)
您可以将消息序列化为JSON格式:
message := iso8583.NewMessage(spec) message.MTI("0100") message.Field(2, "4242424242424242") message.Field(3, "123456") message.Field(4, "100") jsonMessage, err := json.Marshal(message)
它将产生以下JSON(位图未包括, 因为它只用于从二进制表示中解包消息):
{ "0":"0100", "2":"4242424242424242", "3":123456, "4":"100" }
您也可以将JSON解组到iso8583.Message
中:
input := `{"0":"0100","2":"4242424242424242","4":"100"}` message := NewMessage(spec) if err := json.Unmarshal([]byte(input), message); err != nil { // 处理错误 } // 访问单个字段或使用结构体
客户端/服务器(ISO主机和端点)之间的所有消息都有一个消息长度头。它可以是4字节ASCII或2字节BCD编码的长度。我们提供一个network.Header
接口来简化网络头的读写。
支持以下网络头:
您可以从网络连接中读取网络头, 如下所示:
header := network.NewBCD2BytesHeader() _, err := header.ReadFrom(conn) if err != nil { // 处理错误 }
以下是英文到中文的翻译:
// 创建一个缓冲区来保存消息 buf := make([]byte, header.Length()) // 将传入的消息读取到缓冲区中。 read, err := io.ReadFull(conn, buf) if err != nil { // 处理错误 } if reqLen != header.Length() { // 处理错误 }
message := iso8583.NewMessage(specs.Spec87ASCII) message.Unpack(buf)
以下是如何将网络报头写入网络连接的示例:
header := network.NewBCD2BytesHeader() packed, err := message.Pack() if err != nil { // 处理错误 } header.SetLength(len(packed)) _, err = header.WriteTo(conn) if err != nil { // 处理错误 } n, err := conn.Write(packed) if err != nil { // 处理错误 }
CLI支持以下命令:
display
以人类可读的格式显示ISO8583消息iso8583
CLI可以从发布页面下载MacOS、Windows和Linux的可执行文件。
以下是安装MacOS版本的示例:
wget -O ./iso8583 https://github.com/moov-io/iso8583/releases/download/v0.4.6/iso8583_0.4.6_darwin_amd64 && chmod +x ./iso8583
现在您可以运行CLI:
➜ ./iso8583
从命令行无缝使用ISO 8583。
使用方法:
iso8583 <命令> [标志]
可用命令:
describe: 以人类可读的格式显示ISO 8583文件
以人类可读的格式显示ISO8583消息
示例:
➜ ./bin/iso8583 describe msg.bin
MTI........................................: 0100
Bitmap.....................................: 000000000000000000000000000000000000000000000000
Bitmap bits................................: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
F000 Message Type Indicator................: 0100
F002 Primary Account Number................: 4242****4242
F003 Processing Code.......................: 123456
F004 Transaction Amount....................: 100
F020 PAN Extended Country Code.............: 4242****4242
F035 Track 2 Data..........................: 4000****0506=2512111123400001230
F036 Track 3 Data..........................: 011234****3445=724724000000000****00300XXXX020200099010=********************==1=100000000000000000**
F045 Track 1 Data..........................: B4815****1896^YATES/EUGENE L^^^356858 00998000000
F052 PIN Data..............................: 12****78
F055 ICC Data – EMV Having Multiple Tags...: ICC ... Tags
您可以通过spec
标志指定使用哪个内置规范来描述消息:
➜ ./bin/iso8583 describe -spec spec87ascii msg.bin
您还可以以JSON格式定义您自己的规范,并使用spec-file
标志使用该规范文件来描述消息:
➜ ./bin/iso8583 describe -spec-file ./examples/specs/spec87ascii.json msg.bin
请查看JSON规范文件spec87ascii.json的示例。
Apache 许可证 2.0 - 详见 许可证。
一键生成PPT和Word,让学习生活更轻松
讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。
深度推理能力全新升级,全面对标OpenAI o1
科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。
一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型
Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。
字节跳动发布的AI编程神器IDE
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。
AI助力,做PPT更简单!
咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。
选题、配图、成文,一站式创作,让内容运营更高效
讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。
专业的AI公文写作平台,公文写作神器
AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。
OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。
openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。
高分辨率纹理 3D 资产生成
Hunyuan3D-2 是腾讯开发的用于 3D 资产生成的强大工具,支持从文本描述、单张图片或多视角图片生成 3D 模型,具备快速形状生成能力,可生成带纹理的高质量 3D 模型,适用于多个领域,为 3D 创作提供了高效解决方案。
一个具备存储、管理和客户端操作等多种功能的分布式文件系统相关项目。
3FS 是一个功能强大的分布式文件系统项目,涵盖了存储引擎、元数据管理、客户端工具等多个模块。它支持多种文件操作,如创建文件和目录、设置布局等,同时具备高效的事件循环、节点选择和协程池管理等特性。适用于需要大规模数据存储和管理的场景,能够提高系统的性能和可靠性,是分布式存储领域的优质解决方案。
最新AI工具、AI资讯
独家AI资源、AI项目落地
微信扫一扫关注公众号