You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 04:15:07