IT技术家园 - 项目
type: channel
link: https://www.itbunan.xyz/category/xiam/
description: 项目
items: 从零搭建一个手机号过滤平台：PBlack 架构全解析
items: 从零搭建一个短信平台：LESMS 架构全解析
items: 手机号黑名单库查询逻辑与性能优化分享
items: 短信通道管理平台之多层架构与Worker异步处理设计分享
items: CVOICE语音质检系统：一个看板掌控全局，管理看板深度解析
items: 基于Django的录音管理系统的开发总结
items: 爆火的轻量级AI证件照工具HivisionIDPhotos部署过程
items: 支付网关DaxPay部署测试改造过程
items: 新客户端IP一键过白功能开发与配置
items: 为woocommerce开发支付网关插件，对接支付通道

从零搭建一个手机号过滤平台：PBlack 架构全解析
type: item
date: 2026-03-07T09:11:00+00:00
description: 今天聊聊 PBlack——一个开源的手机号黑名单/白名单检测平台。我会从架构设计的角度，拆解它是如何解决这些痛点的，以及为什么选择 Vue + Django + Go 这样的技术组合。为什么需要手机号过滤？先说说背景。在金融风控、电商防刷、社交平台注册这些场景里，手机号是最基础的身份标识。但问题来了：骚扰电话营销：用户被各种推广电话轰炸，体验极差羊毛党批量注册：用虚拟号、接码平台批量薅羊毛欺诈风险：黑名单号码反复作案，平台损失巨大传统的解决方案要么简单粗暴（直接拒接所有陌生号），要么成本太高（每次都要调用第三方接口）。PBlack 的设计目标就是：既要快，又要准，还要省钱。整体架构：三层分离PBlack 采用前后端分离的微服务架构，核心分为三层：┌─────────────────────────────────────────────────────────┐ │ 前端层 (pfront) │ │ Vue 3 + TypeScript + Vite │ │ 管理界面、API 密钥管理、消费统计看板 │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ API 服务层 (papi) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ phone-filter │ │ teddy-api │ │ pfront-api │ │ │ │ -api (Go) │ │ -proxy (Go) │ │ (Go) │ │ │ │ 黑名单检测 │ │ 上游代理 │ │ 认证/消息 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ 数据与管理后台层 │ │ Django + PostgreSQL + Redis │ │ 用户管理、号码库、访问记录、缓存加速 │ └─────────────────────────────────────────────────────────┘这个分层不是拍脑袋决定的。每一层都有自己的职责，而且可以独立部署、独立扩展。技术选型：为什么这样组合？前端：Vue 3 + Vite选择 Vue 3 而不是 React，主要是考虑开发效率和团队熟悉度。Vite 的冷启动速度比 Webpack 快一个数量级，本地开发体验很好。TypeScript 是必须的——手机号过滤涉及大量的 API 接口对接，类型安全能避免很多低级错误。管理后台：DjangoDjango 的 admin 界面是开箱即用的。用户管理、API 密钥管理、黑白名单维护这些功能，用 Django 的 ModelAdmin 几行代码就能搞定。如果用 Go 写后台，光 CRUD 接口就要写一堆。Django 的 ORM 和 admin 在这种场景下是降维打击。核心检测服务：Go这是整个系统的性能瓶颈所在。手机号检测是高频操作，QPS 可能达到几千甚至上万。Go 的 goroutine + channel 模型非常适合这种高并发、低延迟的场景。实测下来，单机可以轻松支撑 10k+ QPS。// 核心检测逻辑：Redis Set 的 O(1) 查询 func (s *BlacklistService) CheckSingleNumber(phone string) (bool, error) { isBlacklisted, err := database.IsPhoneInBlacklistSet(phone) if err != nil { return false, err } s.updateStats(isBlacklisted) return isBlacklisted, nil }数据流转：一次检测请求的全流程来看看一个黑名单检测请求是怎么处理的：客户端 → phone-filter-api → 签名验证 → 用户鉴权 → Redis 查询 ↓ 客户端 ← 返回结果 ← 组装响应 ← 命中判定 ← 黑名单 Set关键设计点：Redis Set 存储：黑名单和白名单分别用 Redis 的 Set 数据结构存储，SISMEMBER 命令是 O(1) 复杂度，百万级号码也能毫秒…

从零搭建一个短信平台：LESMS 架构全解析
type: item
date: 2026-03-02T06:12:00+00:00
description: 短信服务看似简单，但真要自己搭一个能支撑业务运转的平台，坑比想象中多得多。去年有个朋友找我吐槽：公司每个月短信费用好几万，想自建平台省点钱。我反问了他三个问题——高并发怎么扛？通道故障怎么切？账单对不上怎么办？ 他沉默了。这就是短信平台的真相：发一条短信容易，发一亿条还能稳定、安全、可追踪，完全是另一回事。今天聊聊我自己写的 LESMS这个项目，看看一个轻量级企业短信平台是怎么从 0 到 1 搭建起来的。一、为什么要自己搭短信平台？先泼点冷水——大部分公司不需要自建短信平台。直接接阿里云、腾讯云，API 调一下就能用，省心省力。但以下几种情况，自建就有意义了：成本敏感：月发送量过百万，第三方平台的单价和附加费会吃掉不少利润数据合规：金融、医疗行业，用户手机号不能外流到第三方功能定制：需要特殊的签名审核流程、定时发送策略、精细化的通道调度技术储备：团队有能力维护，且业务长期依赖短信触达LESMS 的定位很明确：中小型企业的自建方案，不求大而全，但求核心链路稳、二次开发易。二、三模块架构设计整个系统拆成三大块，每块只干一件事：1. Django 管理后台：业务的"大脑"Django 在这里扮演两个角色：一是客户中心 API。用户注册、登录、余额查询、发送记录查看，这些面向客户的接口都由 Django 提供。用 Django REST Framework（DRF）写起来很快，自带序列化、权限控制、限流。二是运营管理后台。基于 Django Admin 改造的管理界面，运营人员可以在里面审核签名、配置通道、查看统计报表。SimpleUI 美化了一下，至少不像原生 Admin 那么丑。关键模块包括：用户管理：实名认证、企业认证、余额与计费消息管理：模板审核、签名报备、上下行记录通道管理：多运营商通道配置、黑名单管理充值管理：套餐、订单、卡密核销2. Vue 3 前端：用户的"门面"前端用的是 Vue 3 + TypeScript + Element Plus，基于 Vben Admin 框架二次开发。为什么不用 Django 自带的模板？因为现代前端工程化已经成熟了，Vue 的组件复用、状态管理、构建优化都比传统后端渲染强太多。前端主要承载：客户自助服务：发送短信、查看记录、管理通讯录可视化数据：发送成功率、消费趋势、通道质量开发者工具：API 密钥管理、SDK 下载、调试控制台3. Go API 服务：性能的"发动机"这是整个系统的性能担当，用 Go + Gin 框架实现。短信发送有几个特点：高并发、低延迟、重可靠。Django 是同步阻塞模型，处理这种场景比较吃力；Go 的 goroutine + channel 天然适合高并发网络 IO。Go 服务负责的核心功能：短信发送接口：接收请求、校验签名、写入队列Worker 调度：从 Redis 队列取任务，分发到不同运营商通道状态回执：接收运营商的送达报告，更新数据库上行处理：处理用户回复的短信（MO）三、技术选型背后的思考有人可能会问：为什么搞这么复杂，用一种技术栈不行吗？当然行，但会有代价。模块选型理由管理后台Django快速开发、生态成熟、Admin 开箱即用核心 APIGo高并发性能、部署简单、资源占用低前端Vue 3组件化、TypeScript 支持好、团队熟悉数据库PostgreSQLACID 保障、JSON 字段支持、运维友好队列/缓存Redis原子操作丰富、持久化可选、生态完善一句话总结：让合适的工具做合适的事。Django 适合业务逻辑复杂、变更频繁的场景；Go 适合性能敏感、高并发的场景。两者通过 REST API + Redis 队列协作，既保留了各自的优势，又避免了过度耦合。四、一条短信的完整旅程光讲架构有点抽象，我们跟踪一条短信从用户点击"发送"到手机收到的全过程：第一步：前端提交用户在 Vue 界面填写手机号、选择模板、点击发送。前端组装请求体，带上时间戳、nonce、签名，调用 /api/v1/sms/send。第二步：Go 服务接入Go 服务收到请求，依次执行：中间件链：CORS → 日志 → 签名校验 → 限流检查参数校验：手机号格式、模板是否存在、余额是否充足写入队列：将任务序列化后推入 Redis 队列第三步：Worker 调度Worker 进程从队列取出任务：解析手机号前 7 位，识别归属运营商（移动/联通/电信）查询用户的通道配置策略选择最优通道，HTTP 调用运营商网关第四步：运营商处理运营商网关返回提交结果（成功/失败），Worker 记录提交状态。真正的送达是异步的——运营商会在短信送达后推送状态报告。第五步：状态回执运营商回调 Go 服务的 /callback/status 接口，携带手机号、状态、时间戳。Go 服务更新数据库中的发送明…

手机号黑名单库查询逻辑与性能优化分享
type: item
date: 2026-02-27T08:17:00+00:00
description: 在高并发场景下，如何实现毫秒级的手机号黑名单校验？本文将深入剖析一个生产级黑名单系统的核心架构与技术实现。一、总体介绍在短信通道、语音呼叫、风控审核等业务场景中，手机号黑名单校验是一项高频且关键的能力。想象一下，当用户发起呼叫或发送短信时，系统需要在毫秒级时间内判断目标号码是否在黑名单中——这直接关系到业务合规性和用户体验。本文介绍的手机号黑名单库是一个面向运营/风控场景的完整解决方案，具备以下核心特性：双通道架构：Django 管理后台 + Go 高性能 API 服务毫秒级响应：依托 Redis 缓存实现单次查询 < 5ms百万级数据支持：轻松支撑千万级黑名单数据量灵活接入方式：支持单号查询、批量查询（最多 500 个）二、技术要点1. Redis Set 数据结构：空间换时间的极致实践是什么：使用 Redis 的 Set（集合）数据结构存储黑名单手机号，而非传统的 Hash 或 String。为什么这么做：Set 的 SISMEMBER 命令时间复杂度为 O(1)，无论数据量多大，查询性能恒定内存占用优化：存储 1000 万个 11 位手机号仅需约 400MB 内存天然去重：Set 自动处理重复号码，简化业务逻辑核心价值：单机 Redis 可支撑 10 万+ QPS 的查询压力，满足绝大多数业务场景。2. 冷热分离架构：PostgreSQL + Redis 双层存储是什么：PostgreSQL 作为持久化存储（冷数据），Redis 作为查询缓存（热数据）。为什么这么做：数据安全：PostgreSQL 保证数据不丢失，支持事务和备份查询性能：Redis 避免频繁访问数据库，减轻 DB 压力水平扩展：Redis 可部署集群模式，支持数据分片核心价值：兼顾数据可靠性和查询性能，实现"写入慢、读取快"的最优解。3. 原子切换机制：零停机数据更新是什么：使用临时 Set + RENAME 命令实现黑名单数据的无缝切换。为什么这么做：避免更新过程中的数据不一致问题切换操作是原子性的，微秒级完成业务层无感知，零停机时间核心价值：支持百万级数据的全量更新，而不影响线上查询服务。4. Pipeline 批量查询：网络延迟优化是什么：使用 Redis Pipeline 技术批量发送查询命令，减少网络往返次数。为什么这么做：单次网络 RTT 约 1-5ms，批量查询可将 500 个号码的查询时间从 2500ms 降至 10ms减少 Redis 服务器处理开销核心价值：批量查询接口支持 500 个号码一次性校验，响应时间 < 50ms。5. 签名验证机制：API 安全防护是什么：基于 MD5 的参数签名验证，防止接口被恶意调用。为什么这么做：防止请求被篡改（如修改查询号码）防止重放攻击（时间戳有效期 5 分钟）身份认证（AppId + AppSecret 模式）核心价值：确保只有授权用户才能访问黑名单查询服务。三、核心代码片段1. Redis 批量查询实现// BatchIsPhoneInBlacklistSet 使用 Pipeline 批量查询号码是否在黑名单中 func BatchIsPhoneInBlacklistSet(phones []string) (map[string]bool, error) { if len(phones) == 0 { return make(map[string]bool), nil } pipe := RedisClient.Pipeline() cmds := make(map[string]*redis.BoolCmd) // 批量发送 SISMEMBER 命令 for _, phone := range phones { cmds[phone] = pipe.SIsMember(ctx, BlacklistSetKey, phone) } // 执行所有命令（一次网络往返） _, err := pipe.Exec(ctx) if err != nil { return nil, err } // 处理结果 results := make(map[string]bool) for phone, cmd := range cmds { isMember, err := cmd.Result() if err != nil { // 单个查询出错，默认不在黑名单 results[phone] = false } else { results[phone] = isMember } } return results, nil }核心逻辑解读：使用 Pipeline 将多个 SISMEMBER 命令打包发送所有查询共享一次网络往返，大幅降低延迟结果逐个解析，单个失败不影响整体2. 原子切换实现// Atomi…

短信通道管理平台之多层架构与Worker异步处理设计分享
type: item
date: 2026-02-27T07:29:03+00:00
description: 今天来聊聊我们在构建企业级短信平台时的一些架构设计心得。短信服务看似简单，但要在高并发场景下保证稳定性、可观测性和可扩展性，背后的技术选型与架构设计才是关键。一、总体介绍1.1 解决的问题在短信业务中，我们面临几个核心挑战：高并发写入：营销活动期间，短时间内可能有数万条短信发送请求涌入实时性与可靠性的平衡：用户希望短信立即发出，但下游通道往往有速率限制多维度统计：需要实时统计发送量、成功率、计费信息风控合规：黑名单过滤、敏感词检测必须在发送前完成1.2 在平台中的位置本文介绍的架构设计是整个短信平台的"中枢神经"，位于 API 接入层与下游通道之间，承担着请求调度、异步处理、数据持久化的核心职责。1.3 核心价值通过"分层架构 + Worker 异步处理"的设计，我们实现了：解耦：API 层只负责接收请求，具体处理交给 Worker削峰：利用队列缓冲突发流量可扩展：Worker 可以水平扩容可观测：每个组件都有独立的日志输出二、技术要点2.1 三层架构设计我们的平台采用经典的三层架构：┌─────────────────────────────────────────────────────────────┐ │ 前端 (Vue 3) │ │ customer-web - Vben Admin 框架 │ └───────────────────────────┬─────────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────────┐ │ Nginx 反向代理 │ └───────────────┬───────────────────────────┬─────────────────┘ │ │ ┌───────────────▼───────────┐ ┌───────────▼─────────────────┐ │ Django 管理后台 │ │ Go API 服务 │ │ (ladmin) │ │ (lsms-api) │ │ - 用户管理 │ │ - 短信发送 API │ │ - 模板/签名审核 │ │ - 调度器 │ │ - 充值管理 │ │ - Worker 集群 │ │ - 统计报表 │ │ - 计费 Worker │ │ │ │ - 统计 Worker │ │ │ │ - 黑名单 Worker │ └───────────────┬───────────┘ └───────────┬─────────────────┘ │ │ ┌───────────────▼───────────────────────────▼─────────────────┐ │ PostgreSQL + Redis │ │ 数据持久化 + 缓存/队列 │ └─────────────────────────────────────────────────────────────┘技术选型考量：Vue 3 + Vben Admin：现代化前端生态，组件丰富，适合构建复杂的运营后台Django：成熟的企业级后台框架，自带 Admin 界面，适合快速开发管理功能Go API 服务：高并发、低延迟，适合短信发送这类 IO 密集型场景PostgreSQL：ACID 事务、JSONB 支持，适合存储复杂的业务数据Redis：高性能缓存与队列，支撑高并发与解耦2.2 Worker 异步处理机制Worker 是我们架构的核心创新点。当 API 接收到发送请求后，不会立即处理，而是：写入队列：将任务推入 Redis 队列记录日志：在 PostgreSQL 中创建发送记录异步处理：多个 Worker 从队列中拉取任务并行处理flowchart TD Start(["接收发送请求"]) --> Validate["校验签名/限流/鉴权"] Validate --> Enqueue["写入发送队列(Redis)"] Enqueue --> Record["记录发送记录(PostgreSQL)"] Record --> Dispatch["调度器分发任务"] Dispatch --> Billing["计费 Worker 处理"] Dispatch --> Stats["统计 Worker 处理"] Dispatch --> Blacklist["黑名单过滤 Worker 处理"] Billing --> Update["更新计费/余额"] Stats --> UpdateStats["更新统计指标"] Blacklist --> FilterOK{"命中黑名单?"} FilterOK --> |是| Drop["丢弃/标记失败"…

CVOICE语音质检系统：一个看板掌控全局，管理看板深度解析
type: item
date: 2026-02-26T08:26:11+00:00
description: 总体介绍在语音质检系统中，运营管理者面临的最大痛点之一就是信息分散：用户数据、录音状态、敏感词告警、财务消费……分布在不同页面，想要全面了解系统运行状况，需要反复切换、手动汇总。CVOICE语音质检系统的管理看板（Dashboard）正是为解决这一问题而生。它将系统中最核心的运营指标——用户数量、节点状态、录音处理进度、告警消息、财务概览、质检规则排行——全部汇聚在一个页面上，配合可视化图表和实时统计，让管理者打开浏览器就能"一眼看穿"系统全貌。无论是日常巡检还是异常排查，看板都能成为你的"数字驾驶舱"。技术要点1. 后端架构：自定义 Django AdminSiteCVOICE的管理看板并非使用第三方BI工具，而是基于Django Admin框架进行了深度定制。通过继承 AdminSite 类，注册自定义URL，将看板页面无缝嵌入到后台管理系统中：class CustomAdminSite(AdminSite): site_header = '语音质检平台' def get_urls(self): urls = super().get_urls() custom_urls = [ path('dashboard/', self.admin_view(self.dashboard_view), name='dashboard'), path('realtime-stats/', self.admin_view(self.realtime_stats_view), name='realtime_stats'), ] return custom_urls + urls这种方式的好处是：看板天然继承了Django Admin的认证和权限体系，只有经过身份验证的管理员才能访问，无需额外实现鉴权逻辑。2. 多维度数据聚合看板页面在一次请求中完成了超过30项指标的实时计算，覆盖6大维度：维度核心指标数据来源用户管理总用户数、活跃/禁用/欠费分布CUser模型节点状态在线/离线、审核状态分布CUserAgent模型录音处理总量、今日新增、检测状态分布PhoneRecording模型语音转写转写总量、审核状态、质检结果SpeechToText模型告警消息总量、待处理数AlertMessage模型财务统计总余额、累计消费、今日消费ConsumptionRecord模型所有查询均使用Django ORM的 count()、aggregate(Sum()) 和 filter() 链式调用，保持了代码的简洁性和可维护性。3. 可视化图表：Chart.js驱动看板中集成了两类动态图表，均由 Chart.js 4.x 渲染：近7天录音趋势折线图：展示系统整体的录音采集量走势，帮助发现异常波动。节点维度录音趋势：取录音量TOP5的节点，按天展示各自的录音增长曲线，便于定位"高产"或"沉默"节点。图表数据在后端通过循环计算7天内每天的录音数量，序列化为JSON后传递给前端模板：for i in range(6, -1, -1): day = today - timedelta(days=i) day_start = timezone.make_aware(timezone.datetime.combine(day, timezone.datetime.min.time())) day_end = day_start + timedelta(days=1) count = PhoneRecording.objects.filter( created_at__gte=day_start, created_at__lt=day_end ).count() daily_recordings.append(count)4. 质检规则排行榜看板底部设计了质检规则排行榜，从两个角度排名：按录音条数排序：哪条规则命中的录音最多？按总音频时长排序：哪条规则覆盖的通话总时长最长？这为规则优化和资源分配提供了直观的数据支撑。核心代码/配置片段看板的前端采用 Bootstrap 5 构建响应式布局，使用CSS渐变变量统一视觉风格：:root { --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); --success-gradient: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); --warning-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }每个指标卡片通过统一的 stat-card 组件展示，支持趋势标识（如"今日+N"）： {{ total_record…

基于Django的录音管理系统的开发总结
type: item
date: 2024-10-24T12:00:00+00:00
description: 前言安卓手机默认打开了通话录音功能，几年下来积攒了上千条录音，一直懒得清理。最近写了一个管理系统，将所有录音文件导入。进行可视化分析，给自己几年打的所有电话生成一份报告。更直观的展示自己的通讯情况。{card-default label="统计" width="80%"}{/card-default}开发过程录音文件的管理通过django框架开发，主要功能点有通讯录管理、录音文件管理、录音文件转文字管理。转文字通过调用腾讯api完成，将结果保存到数据库，便于查询。可视化模块通过grafana直接读取mysql数据实现。模型类的设计模型类包括三种，Contact类、CallRecord类和RecordResult类。Contact类存储通讯录信息，包含名称和号码等class Contact(models.Model): number = models.CharField(max_length=15,verbose_name='电话号码') # 电话号码 name = models.CharField(blank=True,null=True,max_length=100,verbose_name='联系人') # 联系人姓名 # 新增的类型字段 TYPE_CHOICES = [ ('family', '亲朋'), ('work', '工作'), ('promotion', '推广'), ('taxi', '滴滴'), ('service', '客服'), ('delivery', '快递'), ] contact_type = models.CharField( max_length=10, choices=TYPE_CHOICES, verbose_name='类型', default='promotion', # 默认值为'亲朋' ) def __str__(self): return self.number class Meta: verbose_name = '通讯录' verbose_name_plural = '通讯录'CallRecord类用于存储音频文件、状态、音频转文字的任务信息等class CallRecord(models.Model): phone_number = models.ForeignKey(Contact, related_name='call_records', on_delete=models.CASCADE) # 电话号码外键 call_time = models.DateTimeField(verbose_name='时间') # 通话时间 recording_file = models.CharField(max_length=255, blank=True, null=True, verbose_name='文件名') # 录音文件名 notes = models.TextField(blank=True, null=True, verbose_name='备注') # 备注 task_id = models.CharField(max_length=255, blank=True, null=True, verbose_name='任务id') # 任务ID，可为空 # 状态字段的选择 STATUS_CHOICES = [ ('未处理', '未处理'), # Unprocessed ('处理中', '处理中'), # Processing ('已完成', '已完成'), # Completed ] status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='未处理', verbose_name='状态') # 状态，默认值为 '未处理' def __str__(self): return f"{self.phone_number.number} - {self.call_time}" # 返回通话记录的字符串表示 class Meta: verbose_name = '通话录音' # 该模型的单数名称 verbose_name_plural = '通话录音' # 该模型的复数名称RecordResult用于管理存储音频转文字的结果等信息class RecordResult(models.Model): call_record = models.OneToOneField(CallRecord, related_name='record_result', on_delete=models.CASCADE) # 与 CallRecord 的一对一关系 # 录音时长，单位为秒 duration = …

爆火的轻量级AI证件照工具HivisionIDPhotos部署过程
type: item
date: 2024-09-27T02:52:00+00:00
description: 前言HivisionIDPhotos是一款轻量级的AI证件照制作工具，它利用先进的图像处理技术和机器学习算法，简化了证件照的制作流程，确保生成的照片既符合官方证件的尺寸要求，又保持了高质量。无论是申请护照、驾照还是学生证，我们都可以用它来快速生成符合标准的证件照。{card-default label="制作界面" width="90%"}{/card-default}项目地址： HivisionIDPhotos部署采用docker启动，docker的安装参考以前的教程。部署很简单直接docker启动即可。基本环境docker和docker-compose一键安装脚本项目启动docker-compose up 项目文件:version: '3.8' services: hivision_idphotos: build: context: . dockerfile: Dockerfile image: linzeyi/hivision_idphotos command: python3 -u app.py --host 0.0.0.0 --port 7860 ports: - '3000:7860' hivision_idphotos_api: build: context: . dockerfile: Dockerfile image: linzeyi/hivision_idphotos command: python3 deploy_api.py ports: - '8080:8080'测试访问：http://ip:7860上传一张普通照片，然后即可制作。使用简单，制作质量也可以满足要求。{card-default label="制作效果" width="90%"}{/card-default}

支付网关DaxPay部署测试改造过程
type: item
date: 2024-09-02T09:24:00+00:00
description: 前言DaxPay单商户是一套开源支付网关系统，已经对接支付宝、微信支付相关的接口。可以独立部署，提供接口供业务系统进行调用，不对原有系统产生影响， 适用于小型项目或简单收单的场景。本文记录部署测试记录。{card-default label="收款页面" width="90%"}{/card-default}核心技术栈JDK,1.8+，11版本可以正常使用，但17+版本暂不支持SpingBoot, 2.7xRedis, 5.x版本以上Mysql,5.7.X以上Vue,前端框架3.x项目部署过程数据库mysql,redis的部署过程略过。可以查阅一下往期的文章。本文主要记录项目代码部署的相关过程。所有项目代码的地址： 【支付源码】开源免费支付系统DaxPay源码数据库创建一个daxpay的数据实例。同时在后端项目中_config/sql目录下找到dax-pay.sql数据库脚本文件，导入daxpay数据库。# 建库 mysql -uroot -pmariadb@xxx -h 127.0.0.1 CREATE DATABASE `daxpay` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; create user 'dpuser'@'%' IDENTIFIED BY 'dpuserxxx'; grant all privileges on daxpay.* to 'dpuser'@'%'; flush privileges; # 导入demo数据 mysql -udpuser -pdpuserxxx -h 127.0.0.1 daxpay < ./_config/mysql/dax-pay.sqljava环境利用java和maven打包后端代码，在打包之前修改application.yml内的数据库连接信息。# java和maven的安装 yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel wget https://downloads.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz tar xvf apache-maven-3.8.8-bin.tar.gz mv apache-maven-3.8.8 /usr/local/maven # maven配置国内源 vim ~/.m2/settings.xml 内容见下面... # maven版本验证 java -version mvn -version # 项目打包 mvn -B clean package -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -Dautoconfig.skipmaven国内源：<settings> <mirrors> <mirror> <id>aliyun</id> <mirrorOf>*</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> </mirror> <mirror> <id>hwcloud</id> <mirrorOf>*</mirrorOf> <url>https://mirrors.huaweicloud.com/repository/maven/</url> </mirror> <mirror> <id>tsinghua</id> <mirrorOf>*</mirrorOf> <url>https://mirrors.tuna.tsinghua.edu.cn/maven/</url> </mirror> <mirror> <id>ustc</id> <mirrorOf>*</mirrorOf> <url>https://mirrors.ustc.edu.cn/maven/</url> </mirror> </mirrors> </settings>项目启动项目代码在docker内运行,使用docker-compose.yml管理。docker和docker-compose的安装见往期文章。构建docker镜像:{hide}# java8基础镜像 FROM registry.cn-hangzhou.aliyuncs.com/mybud/java18:lastest # 作者信息 MAINTAINER xxm1995@outlook.com # 时区设置 ENV TZ=Asia/Shanghai RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /…

新客户端IP一键过白功能开发与配置
type: item
date: 2024-08-21T09:08:00+00:00
description: 前言部署了一个自己使用的web服务，不想对公网开放。最初用iptables对自己当前的电脑IP开放，禁止其他IP访问。每次路由器重启，或者在外出差，IP经常变动。需要登录服务器，新增新的IP。决定改变控制方式，利用nginx的IP白名单功能，同时用flask写了一个对公网开放的页面。当地址变动时，访问此页面。点击一键更新，就把最新的ip加入到nginx的白名单。同时重新加载nginx配置生效。{card-default label="ip更新页面" width="85%"}{/card-default}被控制服务需要进行ip访问控制，不对公网开放的nginx配置信息。default.conf配置用加载了ip白名单文件whitelist.conf# Appadmin server { listen 80; server_name 0.0.0.0; root /www/web/maccms_v10/; server_tokens off; #include none.conf; index index.php index.html index.htm; access_log /www/web_logs/wp_access.log wwwlogs; error_log /www/web_logs/wp_error.log notice; #auth_basic "请输入用户和密码"; # 验证时的提示信息 #auth_basic_user_file /etc/nginx/password; # 认证文件 location /{ include whitelist.conf; #默认位置路径为/etc/nginx/ 下， #如直接写include whitelist.conf，则只需要在/etc/nginx目录下创建whitelist.conf deny all; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; include fcgi.conf; } #需要注意伪静态的配置 if (!-e $request_filename) { rewrite ^/index.php(.*)$ /index.php?s=$1 last; rewrite ^/api.php(.*)$ /api.php?s=$1 last; rewrite ^/adm0.php(.*)$ /adm0.php?s=$1 last; rewrite ^(.*)$ /index.php?s=$1 last; break; } location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; } location ~ .*\.(js|css)?$ { expires 12h; } }whitelist.conf文件内存放需要开放的IP,文件内容：allow 101.31.158.153;控制服务文章开头的一键放通页面用flask框架实现, 单独部署app.py主要实现逻辑，有两个接口。一个接口提供页面，一个接口负责获取IP后更新，同时重新加载被控制服务的nginx配置{hide}from flask import Flask, request, render_template, jsonify import os app = Flask(__name__) # 定义首页路由，渲染包含按钮的HTML页面 @app.route('/') def index(): return render_template('index.html') # 定义处理客户端IP上传的路由 @app.route('/upload_ip', methods=['POST']) def upload_ip(): # 获取客户端的IP地址 #client_ip = request.remote_addr client_ip = request.headers.get('X-Forwarded-For') # 这里可以添加处理逻辑，比如将IP地址保存到数据库或文件 print(f"Client IP: {client_ip}") try: command = f"echo 'allow {client_ip};' > /srv/lnmp/services/nginx/conf/whitelist.conf && docker exec lnmp-web-1 /bin/bash -c 'nginx -s reload'" status = os.system(command) if status == 0: response = {'status': 'success'…

为woocommerce开发支付网关插件，对接支付通道
type: item
date: 2024-08-10T04:08:20+00:00
description: 前言WooCommerce模板众多，可以选择出我们需要的模板，生态好，而且数千个钩子更加利于开发者开发。本文分享如何为woocommerce独立站开发第三方支付插件。创建插件因为WooCommerce有很多的钩子，所以我们在开发支付网关的时候，只需按照一个“框架”来开发就好，下面的是插件框架<?php /* * Plugin Name: WooCommerce自定义支付网关 * Plugin URI: https://www.kekc.cn/ * Description: 这个插件是我们开发自定义支付网关时的示例插件 * Author: kekc * Author URI: https://www.kekc.cn * Version: 1.0.0 */ /* * 这个动作钩子将我们的PHP类注册为WooCommerce的支付网关 */ add_filter( 'woocommerce_payment_gateways', 'kekc_cn_add_gateway_class' ); function kekc_cn_add_gateway_class( $gateways ) { $gateways[] = 'WC_kekc_cn_Gateway'; // 类似一个支付别名 return $gateways; } /* * 注意它是在plugins_loaded动作钩子里面的，也就是插件加载时的hook */ add_action( 'plugins_loaded', 'kekc_cn_init_gateway_class' ); function kekc_cn_init_gateway_class() { class WC_kekc_cn_Gateway extends WC_Payment_Gateway { /** * 从这里开始执行，我们先放在这，之后详细讲 */ public function __construct() { ... } /** * 插件选项，也就是插件的设置页面的设置项，也在之后详细说 */ public function init_form_fields(){ ... } /** * 支付字段，填一些表单数据，字段等，比如用信用卡支付的信用卡号之类的 */ public function payment_fields() { ... } /* * 自定义CSS和JS，在大多数情况下，只有当你决定使用自定义支付字段时才需要。 */ public function payment_scripts() { ... } /* * 字段验证 */ public function validate_fields() { ... } /* * 在这里处理付款 */ public function process_payment( $order_id ) { ... } /* * 如果你需要一个webhook，如PayPal IPN等，可以新建个函数，以便在其他函数中使用它 */ public function webhook() { ... } } }具体代码构造函数public function __construct() { $this->id = 'kekc_cn'; // 支付网关插件ID，可以字符串，但是要唯一 $this->icon = ''; // 将显示在结账页上你的支付网关图标。内容为URL $this->has_fields = true; // 你需要自定义支付网关字段就填true $this->method_title = 'kekc_cn Gateway'; $this->method_description = 'Description of kekc_cn payment gateway'; // 显示在选项页上 // 网关可以支持订阅、退款、保存支付方式。 // 但在本教程中，我们从简单的支付开始 $this->supports = array( 'products' ); // 所有选项字段的方法 $this->init_form_fields(); // 加载设置 $this->init_settings(); $this->title = $this->get_option( 'title' ); $this->description = $this->get_option( 'description' ); $this->enabled = $this->get_option( 'enabled' ); $this->testmode = 'yes' === $this->get_option( 'testmode' ); $this->private_key = $t…