Laravel 8集成EasyPost实现电商结算页运费查询方案咨询
Laravel 结合 EasyPost 实现结算页运费展示的完整流程
1. 前期准备工作
- 通过composer安装EasyPost官方SDK:
composer require easypost/easypost-php - 在
.env文件中配置EasyPost密钥:EASYPOST_API_KEY=你的测试/正式密钥,测试阶段使用测试密钥不会产生真实费用 - 提前在配置文件中存好仓库发货地址的基础参数,避免每次请求重复创建地址对象
- 确保商品模型中已预存每件商品的重量、尺寸字段,单位和EasyPost要求的单位对齐
2. 封装运费查询逻辑
建议先创建独立Service层封装EasyPost调用逻辑,避免控制器代码冗余,新建app/Services/EasyPostShippingService.php,核心代码参考:
use EasyPost\EasyPost; use EasyPost\Shipment; class EasyPostShippingService { public function __construct() { EasyPost::setApiKey(env('EASYPOST_API_KEY')); } // 传入收货地址、包裹信息返回可用运费选项 public function getShippingRates($toAddress, $parcels) { // 创建收货地址对象 $toAddress = \EasyPost\Address::create($toAddress); // 读取预配置的发货地址 $fromAddress = \EasyPost\Address::create(config('shipping.from_address')); // 创建货件查询运费 $shipment = Shipment::create([ 'to_address' => $toAddress, 'from_address' => $fromAddress, 'parcels' => $parcels ]); // 过滤返回需要的字段,按运费金额排序 return collect($shipment->rates)->map(function($rate) { return [ 'carrier' => $rate->carrier, 'service' => $rate->service, 'rate' => (float)$rate->rate, 'est_delivery_days' => $rate->est_delivery_days, 'rate_id' => $rate->id ]; })->sortBy('rate')->values(); } }
3. 路由与控制器配置
3.1 路由配置
在routes/web.php添加对应路由:
- 结算页展示路由:
Route::get('/checkout', [CheckoutController::class, 'index'])->name('checkout.index'); - 异步运费查询接口:
Route::post('/checkout/get-shipping-rates', [CheckoutController::class, 'getShippingRates'])->name('checkout.get_shipping_rates'); - 运费选择提交接口:
Route::post('/checkout/select-shipping', [CheckoutController::class, 'selectShipping'])->name('checkout.select_shipping');
3.2 控制器逻辑
新建app/Http/Controllers/CheckoutController.php,核心逻辑参考:
use App\Services\EasyPostShippingService; use Gloudemans\Shoppingcart\Facades\Cart; use Illuminate\Http\Request; class CheckoutController extends Controller { protected $shippingService; public function __construct(EasyPostShippingService $shippingService) { $this->shippingService = $shippingService; } public function index() { $cartItems = Cart::content(); $subtotal = Cart::subtotal(2, '.', ''); // 加载页面时如果有默认收货地址直接查询初始运费 $defaultAddress = auth()->user()->addresses->where('is_default', 1)->first(); $shippingRates = $defaultAddress ? $this->shippingService->getShippingRates( $defaultAddress->toArray(), $this->getParcelsFromCart($cartItems) ) : []; return view('checkout.index', compact('cartItems', 'subtotal', 'shippingRates', 'defaultAddress')); } // 把购物车商品转换为EasyPost要求的parcel格式 protected function getParcelsFromCart($cartItems) { $parcels = []; foreach ($cartItems as $item) { // 多件同商品直接叠加重量,也可以按你的打包规则合并包裹 $parcels[] = [ 'length' => $item->model->length, 'width' => $item->model->width, 'height' => $item->model->height, 'weight' => $item->model->weight * $item->qty ]; } return $parcels; } // 用户修改收货地址时异步查询运费 public function getShippingRates(Request $request) { $validated = $request->validate([ 'street1' => 'required', 'city' => 'required', 'state' => 'required', 'zip' => 'required', 'country' => 'required' ]); $rates = $this->shippingService->getShippingRates( $validated, $this->getParcelsFromCart(Cart::content()) ); return response()->json($rates); } // 保存用户选中的运费选项到session public function selectShipping(Request $request) { session()->put('selected_shipping', [ 'rate_id' => $request->rate_id, 'rate' => $request->rate, 'carrier' => $request->carrier, 'service' => $request->service ]); // 计算最新订单总价返回前端 $total = Cart::subtotal(2, '.', '') + $request->rate; return response()->json(['total' => number_format($total, 2)]); } }
4. 前端交互逻辑
- 页面加载时如果有初始运费列表,直接渲染为单选按钮供用户选择;未填写收货地址时提示用户填写后查看运费
- 监听收货地址修改事件,填写完成后异步调用运费查询接口刷新运费选项
- 用户选择某一运费选项时,异步调用选择接口,实时更新页面上的运费金额和订单总价
- 提交订单前校验session中必须存在已选择的运费信息,避免用户跳过选择
5. 订单生成处理
- 生成订单时,将session中存储的运费信息、运费金额写入订单表对应字段,订单总价=商品小计+运费
- 后续需要打印运单时,直接用订单中存储的
rate_id调用EasyPost的运单生成接口即可,无需重复查询运费
内容的提问来源于stack exchange,提问作者D.T
相关产品推荐
相关产品推荐

