fix(order-service): 修复包含 Emoji 和孤立代理字符的订单在 PostgreSQL jsonb 下报错导致死循环重试进单的问题
1. 在 utils/json.ts 新增 sanitizeWellFormedUnicode、deepSanitizeUnicode 和 safeJsonStringify,自动清理空字节 (\0) 并将畸变孤立 UTF-16 代理字符 (Lone Surrogates) 安全转换为规范字符,杜绝 PostgreSQL jsonb 解析错误; 2. 拼多多订单映射器与通用进单服务 (order-service) 全面接入 Unicode 深度清洗与安全序列化,确保买家昵称/留言中的各类特殊 Emoji 和生僻字符平滑落库; 3. 数据库仓储层 (order-repo / order-item-repo) 针对 raw_payload_json、spec_json、item_snapshot_json 等 jsonb 字段增加兜底安全序列化保护; 4. 补充 utils/json.test.ts 与 pdd-order-mapper.test.ts 单元测试,覆盖畸变字符与空字节场景。
This commit is contained in:
@@ -3,6 +3,7 @@ import type { PoolClient, QueryResult } from 'pg'
|
||||
import { query, withTransaction } from '../db/client.js'
|
||||
import type { OrderItemReplaceInput } from '../types/repository/inputs.js'
|
||||
import type { OrderItemRow } from '../types/repository/rows.js'
|
||||
import { safeJsonStringify } from '../utils/json.js'
|
||||
|
||||
export type QueryExecutor = (text: string, params?: unknown[]) => Promise<QueryResult<any>>
|
||||
|
||||
@@ -71,8 +72,8 @@ export async function replaceOrderItemsWithExecutor(
|
||||
update.item.skuCode,
|
||||
update.item.skuName,
|
||||
update.item.quantity,
|
||||
update.item.specJson || '{}',
|
||||
update.item.itemSnapshotJson || update.item.specJson || '{}',
|
||||
safeJsonStringify(update.item.specJson || '{}'),
|
||||
safeJsonStringify(update.item.itemSnapshotJson || update.item.specJson || '{}'),
|
||||
update.item.updatedAt,
|
||||
update.orderItemId,
|
||||
],
|
||||
@@ -98,8 +99,8 @@ export async function replaceOrderItemsWithExecutor(
|
||||
create.skuCode,
|
||||
create.skuName,
|
||||
create.quantity,
|
||||
create.specJson || '{}',
|
||||
create.itemSnapshotJson || create.specJson || '{}',
|
||||
safeJsonStringify(create.specJson || '{}'),
|
||||
safeJsonStringify(create.itemSnapshotJson || create.specJson || '{}'),
|
||||
create.createdAt,
|
||||
create.updatedAt,
|
||||
],
|
||||
|
||||
@@ -8,6 +8,7 @@ import type {
|
||||
} from '../types/repository/inputs.js'
|
||||
import type { OrderListQueryResult, OrderListRow, OrderRow } from '../types/repository/rows.js'
|
||||
import { isPlatformOrderIdLookupKeyword } from '../utils/platform-order-id.js'
|
||||
import { safeJsonStringify, sanitizeWellFormedUnicode } from '../utils/json.js'
|
||||
|
||||
export type OrderQueryExecutor = <T extends QueryResultRow = QueryResultRow>(
|
||||
text: string,
|
||||
@@ -147,12 +148,12 @@ export async function createOrderWithExecutor(
|
||||
input.platformOrderId,
|
||||
input.orderStatus,
|
||||
input.payStatus,
|
||||
input.buyerId,
|
||||
input.buyerName,
|
||||
input.receiverContact,
|
||||
sanitizeWellFormedUnicode(input.buyerId),
|
||||
sanitizeWellFormedUnicode(input.buyerName),
|
||||
sanitizeWellFormedUnicode(input.receiverContact),
|
||||
input.totalAmount,
|
||||
input.currency,
|
||||
input.rawPayloadJson || '{}',
|
||||
safeJsonStringify(input.rawPayloadJson || '{}'),
|
||||
input.paidAt || null,
|
||||
input.createdAt,
|
||||
input.updatedAt,
|
||||
@@ -202,12 +203,12 @@ export async function updateOrderWithExecutor(
|
||||
input.shopName,
|
||||
input.orderStatus,
|
||||
input.payStatus,
|
||||
input.buyerId,
|
||||
input.buyerName,
|
||||
input.receiverContact,
|
||||
sanitizeWellFormedUnicode(input.buyerId),
|
||||
sanitizeWellFormedUnicode(input.buyerName),
|
||||
sanitizeWellFormedUnicode(input.receiverContact),
|
||||
input.totalAmount,
|
||||
input.currency,
|
||||
input.rawPayloadJson || '{}',
|
||||
safeJsonStringify(input.rawPayloadJson || '{}'),
|
||||
input.paidAt || null,
|
||||
input.updatedAt,
|
||||
Number(orderId),
|
||||
|
||||
Reference in New Issue
Block a user