简化开放下单幂等参数
This commit is contained in:
@@ -56,11 +56,6 @@ func (h *OpenV1Handler) CreateOrder(c *gin.Context) {
|
||||
response.BadRequest(c, "参数错误:client_order_no 与 sku 必填")
|
||||
return
|
||||
}
|
||||
if key := c.GetHeader("Idempotency-Key"); key != "" && key != req.ClientOrderNo {
|
||||
openlog.Warn(c, "create_order idempotency_key_mismatch header=%s body=%s", key, req.ClientOrderNo)
|
||||
response.BadRequest(c, "Idempotency-Key 必须与 client_order_no 一致")
|
||||
return
|
||||
}
|
||||
var data interface{}
|
||||
if len(req.Data) > 0 {
|
||||
var decoded interface{}
|
||||
|
||||
@@ -36,7 +36,7 @@ func Setup(h *Handlers) *gin.Engine {
|
||||
r.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
||||
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-Merchant-ID", "X-App-Key", "X-Api-Key", "X-Timestamp", "X-Nonce", "X-Sign", "Idempotency-Key", "X-Request-ID"},
|
||||
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-Merchant-ID", "X-App-Key", "X-Api-Key", "X-Timestamp", "X-Nonce", "X-Sign", "X-Request-ID"},
|
||||
ExposeHeaders: []string{"Content-Length", "X-Request-ID"},
|
||||
AllowCredentials: true,
|
||||
}))
|
||||
|
||||
@@ -201,7 +201,7 @@ export const endpoints: EndpointSpec[] = [
|
||||
summary: '幂等创建订单并扣款(成功返回 201,重复请求返回 200 且 idempotent=true)',
|
||||
scope: 'orders:write',
|
||||
bodyParams: [
|
||||
{ name: 'client_order_no', type: 'string', required: true, desc: '调用方幂等单号,需与 Idempotency-Key 一致', example: 'shop-10001' },
|
||||
{ name: 'client_order_no', type: 'string', required: true, desc: '调用方幂等单号,同一商户下唯一', example: 'shop-10001' },
|
||||
{ name: 'sku', type: 'string', required: true, desc: '商品标识,取自商品列表', example: 'suit_pink_sheep' },
|
||||
{ name: 'quantity', type: 'int', desc: '数量,默认 1', example: '1' },
|
||||
{ name: 'buyer_reference', type: 'string', desc: '买家标识/备注', example: 'buyer-001' },
|
||||
@@ -233,7 +233,7 @@ export const endpoints: EndpointSpec[] = [
|
||||
{ name: 'order', type: 'object', desc: '订单对象,字段见「订单字段说明」' },
|
||||
],
|
||||
notes: [
|
||||
'Header 需带 Idempotency-Key,且必须与 client_order_no 一致。',
|
||||
'client_order_no 是唯一幂等单号,请保证同一商户下不重复。',
|
||||
'下单即扣款(payment_status=paid),余额不足返回 400。',
|
||||
'同一 client_order_no 重复请求不会重复扣款,返回 idempotent=true。',
|
||||
],
|
||||
|
||||
@@ -77,7 +77,6 @@ export default function ApiDebugger() {
|
||||
const [pathValues, setPathValues] = useState<Record<string, string>>({})
|
||||
const [queryValues, setQueryValues] = useState<Record<string, string>>({})
|
||||
const [bodyText, setBodyText] = useState('')
|
||||
const [idempotencyKey, setIdempotencyKey] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const handleAppKeyChange = (val: string) => {
|
||||
@@ -114,7 +113,6 @@ export default function ApiDebugger() {
|
||||
} | null>(null)
|
||||
|
||||
const endpoint = endpoints.find((e) => e.key === selectedKey)
|
||||
const isCreateOrder = selectedKey === 'create-order'
|
||||
|
||||
useEffect(() => {
|
||||
if (endpoint?.requestExample) {
|
||||
@@ -129,7 +127,6 @@ export default function ApiDebugger() {
|
||||
}
|
||||
setPathValues({})
|
||||
setQueryValues({})
|
||||
setIdempotencyKey('')
|
||||
setResponse(null)
|
||||
setSignInfo(null)
|
||||
}, [selectedKey, endpoint])
|
||||
@@ -192,9 +189,6 @@ export default function ApiDebugger() {
|
||||
if (method !== 'GET' && bodyText) {
|
||||
fetchHeaders['Content-Type'] = 'application/json'
|
||||
}
|
||||
if (isCreateOrder && idempotencyKey.trim()) {
|
||||
fetchHeaders['Idempotency-Key'] = idempotencyKey.trim()
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
const start = performance.now()
|
||||
@@ -363,16 +357,6 @@ export default function ApiDebugger() {
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
{isCreateOrder && (
|
||||
<Form.Item label={<Text code style={{ fontSize: 14 }}>Idempotency-Key</Text>} help="须与 client_order_no 一致">
|
||||
<Input
|
||||
value={idempotencyKey}
|
||||
onChange={(e) => setIdempotencyKey(e.target.value)}
|
||||
style={{ maxWidth: 480 }}
|
||||
placeholder="会从 Request Body 自动取 client_order_no"
|
||||
/>
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form>
|
||||
|
||||
<Alert
|
||||
|
||||
@@ -425,7 +425,7 @@ app_key=ak_xxx&body_sha256=<实际请求 body 字节的 SHA256 十六进制>&met
|
||||
<li>POST 签名用的 <Text code>body</Text> 必须与实际发送的 body <b>字节级一致</b>,不要签名后再改空格或字段顺序。</li>
|
||||
<li>value <b>不要</b> URL encode,原样参与拼接。</li>
|
||||
<li>签名失败常见原因:secret 错、path 多了 query、body 与签名不一致、时间戳过期、nonce 重复、参数未按字典序拼接。</li>
|
||||
<li>下单接口还需携带 <Text code>Idempotency-Key</Text>,且必须与 <Text code>client_order_no</Text> 一致。</li>
|
||||
<li>下单幂等直接使用 <Text code>client_order_no</Text>,无需额外 Header。</li>
|
||||
</ul>
|
||||
}
|
||||
/>
|
||||
@@ -495,7 +495,7 @@ function StatusSection() {
|
||||
description={
|
||||
<pre className="api-docs__pre api-docs__pre--plain">{`拿到 sku(商品列表)
|
||||
↓
|
||||
POST /orders 下单(幂等,Idempotency-Key = client_order_no)
|
||||
POST /orders 下单(client_order_no 幂等)
|
||||
↓
|
||||
拿响应里的 order_no 进入发货平台链接
|
||||
↓
|
||||
|
||||
Reference in New Issue
Block a user