完整下单流程
分类: 科技创建于: 6/5/2025
网上商城的商品详情页到最终支付完毕的整个流程,涉及多个页面跳转、数据传递和后端逻辑。下面将详细解析每个步骤:
1. 商品详情页 (Product Detail Page - PDP)
- 页面 URL 示例:
/products/{productId}
或/product?id={productId}
- 用户操作: 用户浏览商品,查看商品图片、描述、价格、规格(如颜色、尺寸),并决定购买。
- 参数传递 (初次加载):
productId
(通过 URL 路径参数或查询参数传递):用于后端从数据库中获取商品的所有详细信息。
- 后端逻辑:
- 根据
productId
从products
表和相关联的product_variants
、product_images
表中查询商品数据。 - 将查询到的数据渲染到前端页面。
- 根据
2. 加入购物车 (Add to Cart)
- 页面 URL 示例: 通常停留在 PDP 或弹出提示,也可能直接跳转到购物车页面。
- 用户操作: 点击“加入购物车”按钮。
- 参数传递 (POST 请求):
- 前端向后端发送的数据 (通常通过 AJAX POST 请求到
/cart/add
):productId
: 商品 ID。quantity
: 购买数量。variantId
(可选): 如果商品有规格(如颜色、尺寸),则传递所选规格的 ID。
- 前端向后端发送的数据 (通常通过 AJAX POST 请求到
- 后端逻辑:
- 接收到 POST 请求。
- 验证
productId
、quantity
、variantId
是否合法,并检查库存。 - 更新购物车数据:
- 如果用户已登录: 将商品信息与
user_id
关联,存储到数据库的carts
和cart_items
表中。 - 如果用户是访客: 将购物车数据存储在用户的
Session
中或通过Cookie
关联到数据库中的访客购物车。
- 如果用户已登录: 将商品信息与
- 返回成功响应(例如,JSON 格式的成功消息,或者重定向到购物车页面)。
3. 购物车页面 (Shopping Cart Page)
- 页面 URL 示例:
/cart
- 用户操作: 查看购物车中的商品列表、修改商品数量、删除商品,然后点击“去结算”或“继续购物”。
- 参数传递 (初次加载):
- 无需 URL 参数。后端根据用户的登录状态(
user_id
from session)或访客session_id
/cookie_id
从数据库或 Session 中获取购物车数据。
- 无需 URL 参数。后端根据用户的登录状态(
- 后端逻辑:
- 根据
user_id
或session_id
检索购物车中的所有商品及数量。 - 从
products
和product_variants
表中获取商品的详细信息(如名称、价格、图片)。 - 计算购物车中所有商品的总价(小计)。
- 根据
- 参数传递 (更新):
- 用户修改数量或删除商品时,通常通过 AJAX (PUT/DELETE 请求) 传递
cartItemId
和newQuantity
或cartItemId
到后端。
- 用户修改数量或删除商品时,通常通过 AJAX (PUT/DELETE 请求) 传递
- 参数传递 (去结算): 点击“去结算”按钮时,通常是 GET 或 POST 请求到
/checkout
,不需额外参数,因为购物车数据已在后端关联。
4. 结算流程 - 填写收货地址 / 用户信息 (Checkout - Shipping Address)
- 页面 URL 示例:
/checkout/shipping
- 用户操作: 填写收货人姓名、手机、详细地址、省市区等信息。可能还会询问是否需要填写发票信息或选择送货时间。
- 参数传递 (初次加载):
- 无需 URL 参数。如果用户已登录且有保存的地址,后端会预先填充。
- 后端逻辑:
- 如果用户已登录,从
addresses
表中获取用户常用地址并展示。 - 验证并保存地址: 接收前端 POST 提交的地址信息,进行数据验证(格式、完整性),并将地址信息暂时存储在用户的
Session
或一个临时的checkout_sessions
数据库表中,关联当前购物车/订单。
- 如果用户已登录,从
- 参数传递 (POST):
- 用户提交表单时,通过 POST 请求向
/checkout/shipping
传递所有表单字段,如fullName
,addressLine1
,city
,state
,zipCode
,phoneNumber
,email
等。
- 用户提交表单时,通过 POST 请求向
5. 结算流程 - 选择配送方式 (Checkout - Shipping Method)
- 页面 URL 示例:
/checkout/shipping-method
- 用户操作: 根据商品重量、收货地址、时效等选择不同的配送方式(如普通快递、顺丰、EMS 等)。
- 参数传递 (初次加载):
- 无需 URL 参数。
- 后端逻辑:
- 根据用户之前填写的收货地址和购物车商品信息(重量、体积),查询可用的配送方式(从
shipping_methods
表或第三方物流 API)。 - 计算不同配送方式的运费和预计送达时间。
- 保存选择: 将用户选择的配送方式和运费存储在
Session
或checkout_sessions
表中。
- 根据用户之前填写的收货地址和购物车商品信息(重量、体积),查询可用的配送方式(从
- 参数传递 (POST):
- 用户选择配送方式后,通过 POST 请求向
/checkout/shipping-method
传递selectedShippingMethodId
。
- 用户选择配送方式后,通过 POST 请求向
6. 结算流程 - 选择支付方式 (Checkout - Payment Method)
- 页面 URL 示例:
/checkout/payment
- 用户操作: 选择支付方式(如支付宝、微信支付、银联、信用卡等)。
- 参数传递 (初次加载):
- 无需 URL 参数。
- 后端逻辑:
- 展示所有可用的支付方式。
- 如果是信用卡支付,通常会集成支付网关的客户端 SDK (如 Stripe.js, PayPal SDK),在前端安全地获取信用卡信息并生成一个临时的
paymentToken
,而不是直接将卡号发送到商户服务器。 - 保存选择: 将用户选择的支付方式类型存储在
Session
或checkout_sessions
表中。
- 参数传递 (POST):
- 用户选择支付方式后,通过 POST 请求向
/checkout/payment
传递selectedPaymentMethodType
,如果是信用卡,则包含支付网关返回的paymentToken
。
- 用户选择支付方式后,通过 POST 请求向
7. 订单确认 / 预览页面 (Order Confirmation/Review Page)
- 页面 URL 示例:
/checkout/review
- 用户操作: 在提交订单前,最后一次核对所有订单信息:商品列表、收货地址、配送方式、支付方式、总金额(含运费)。确认无误后点击“提交订单”或“立即支付”。
- 参数传递 (初次加载):
- 无需 URL 参数。所有信息从
Session
或checkout_sessions
表中读取。
- 无需 URL 参数。所有信息从
- 后端逻辑:
- 从
Session
或checkout_sessions
表中检索所有已收集的订单信息。 - 进行最终的库存检查和价格计算(包括运费、可能的优惠券、税费)。
- 将所有信息渲染到页面上供用户确认。
- 从
8. 处理支付 / 跳转支付网关 (Process Payment / Payment Gateway Redirection)
- 页面 URL 示例: 通常不是直接的页面,而是后端处理或跳转。
- 用户操作: 点击“立即支付”按钮。
- 参数传递 (后端到支付网关):
- 前端向后端发送数据 (POST): 通常是简单的请求到
/checkout/place-order
,后端会从 Session 中获取所有订单详情。 - 后端向支付网关发送数据 (API 调用或重定向参数):
amount
: 订单总金额。currency
: 货币类型。orderId
: 商城内部生成的唯一订单号。description
: 订单描述。customerInfo
: 用户信息(邮箱、电话、收货地址等)。paymentToken
(如果使用信用卡支付): 前端通过网关 SDK 生成的临时支付令牌。return_url
: 支付成功后支付网关将用户重定向回商城的回调 URL。cancel_url
: 支付失败或用户取消后将用户重定向回商城的回调 URL。
- 前端向后端发送数据 (POST): 通常是简单的请求到
- 后端逻辑:
- 创建待支付订单: 将所有订单信息(商品、地址、运费、总价等)写入
orders
表,并将订单状态设置为pending
(待支付)。 - 调用支付网关 API: 根据选择的支付方式,调用相应的支付网关 API。
- 直接支付 (如信用卡): 如果是直接API调用(如Stripe的Charge API),后端直接向支付网关发送支付请求,并根据网关返回的结果更新订单状态。
- 跳转支付 (如支付宝、微信、PayPal): 后端根据支付网关的要求,生成一个支付请求参数,然后指示前端(通过 HTTP 302 重定向)跳转到支付网关的支付页面,并携带必要的参数。
- 创建待支付订单: 将所有订单信息(商品、地址、运费、总价等)写入
9. 支付网关响应 / 支付结果页面 (Payment Gateway Response / Success/Failure Page)
- 页面 URL 示例:
return_url
(成功):/payment/success?orderId=XYZ&transactionId=ABC
cancel_url
(失败):/payment/failure?orderId=XYZ&errorCode=123
- 用户操作: 在支付网关完成支付或取消支付后,被重定向回商城。
- 参数传递 (支付网关到后端):
- GET/POST 参数 (从网关回调到
return_url
/cancel_url
):transactionId
: 支付网关生成的交易 ID。orderId
: 商城内部的订单 ID(由商城在跳转时传递给网关,网关再传回来)。status
: 支付结果状态(成功、失败、处理中等)。signature
: 用于验证回调合法性的签名(重要!)。
- Webhooks (后端到后端):
- 最可靠的方式。 支付网关在支付成功/失败后,会向商城预先配置的
webhook
URL 发送一个服务器到服务器的通知(通常是 POST 请求)。这个通知包含完整的支付状态信息。
- 最可靠的方式。 支付网关在支付成功/失败后,会向商城预先配置的
- GET/POST 参数 (从网关回调到
- 后端逻辑 (Webhook Endpoint):
- 接收支付网关的 Webhook 通知。
- 验证 Webhook 的合法性(通常通过签名)。
- 根据通知中的
transactionId
和orderId
,更新orders
表中的订单状态(paid
、failed
、refunded
等)。 - 触发后续流程:发送订单确认邮件、通知仓库发货、更新库存等。
- 后端逻辑 (Return URL Endpoint):
- 用户浏览器被重定向回来后,后端根据 URL 中的参数查询
orders
表。 - 显示相应的支付成功或失败页面。
- 注意: 回调页面的作用主要是给用户展示结果,真正的订单状态更新应依赖 Webhook,因为用户可能在回调前关闭浏览器。
- 用户浏览器被重定向回来后,后端根据 URL 中的参数查询
10. 订单完成页 (Order Complete Page)
- 页面 URL 示例:
/order/complete?id={orderId}
- 用户操作: 查看订单已完成的确认信息。
- 参数传递 (初次加载):
orderId
(通过 URL 查询参数):用于后端从数据库中获取已完成的订单详情。
- 后端逻辑:
- 根据
orderId
从orders
表和相关联的order_items
、shipping_addresses
等表中查询完整的订单信息。 - 在页面上显示“感谢您的订单”、“订单号:XXXXX”、“预计发货时间”等信息。
- 清理用户的购物车(如果尚未清理)。
- 可能提供查看订单详情、跟踪物流等链接。
- 根据
总结要点
- 安全性:
- 全程使用 HTTPS/SSL。
- 敏感信息(如信用卡号)绝不直接存储在商户服务器,而是通过支付网关的 Token 化处理或直接跳转到网关页面。
- 所有接收到的数据(特别是来自支付网关的回调)都必须进行签名验证,以防篡改和伪造。
- 严格的输入验证和防范 SQL 注入、XSS 等攻击。
- 数据流向:
- 前端 -> 后端: 用户操作和输入的数据,通常通过 POST 请求。
- 后端 -> 数据库: 存储购物车、订单、地址等信息。
- 后端 <-> 支付网关: 服务器到服务器的 API 调用进行支付处理,或者通过重定向。
- 支付网关 -> 后端 (Webhooks): 最可靠的支付状态更新机制。
- 支付网关 -> 前端 (重定向): 用户返回商城页面。
- 用户体验 (UX):
- 清晰的结算流程步骤指示(如多步进度条)。
- 表单验证提示及时准确。
- 移动端友好。
- 友好的错误提示。
- 状态管理:
- 订单状态在整个流程中不断变化(待支付、已支付、已发货、已完成等),需要准确更新。
- 购物车、地址、支付方式等信息在结算过程中需要保存在 Session 或临时数据库表中。
- 幂等性 (Idempotency):
- 向支付网关发送的请求应设计为幂等的,即多次发送相同的请求只处理一次,避免重复扣款。
- 并发与库存:
- 在加入购物车和提交订单时需要进行库存检查,并考虑高并发下的库存扣减机制。
- 实际库存扣减通常发生在支付成功后。
这是一个复杂但有序的流程,每一步都环环相扣,确保购物体验的顺畅和交易的安全性。