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

如何通过Shopify API获取全部1300个变体?分页遇状态0错误

Shopify API分页获取变体失败(状态0错误)修复方案

问题背景

需要从Shopify API获取全部1300个变体插入自定义表,但默认请求仅返回50条,实现分页时出现状态0错误,无法继续拉取后续数据。

代码问题排查

原代码存在以下几个关键问题导致分页失败:

  • 请求对象复用污染:循环中复用同一个HttpRequestMessage实例,可能残留上一次请求的参数,引发请求异常
  • 鉴权Token无效:Shopify记录未执行初始化操作(如FindFirst()),导致Shopify.Token为空,请求鉴权失败
  • Link Header解析逻辑错误:遍历Link Header时重复使用变量名LinkPart,导致分页URL提取逻辑混乱;且未兼容Shopify Link Header中引号的不同格式
  • 错误信息缺失:请求失败时仅输出状态码,状态0通常表示请求未发送成功,无法定位具体原因
  • 代码冗余:插入记录的逻辑在分支中完全重复,可简化

修复后的完整代码

procedure InsertVariants()
var
    Client: HttpClient;
    Request: HttpRequestMessage;
    Response: HttpResponseMessage;
    Content: HttpContent;
    JsonResponse: Text;
    JsonObject: JsonObject;
    JsonArray: JsonArray;
    JsonToken: JsonToken;
    VariantObject: JsonObject;
    TempToken: JsonToken;
    ShopifyVariantRecord: Record "Shopify Variants Mercalab";
    VariantIdInteger: BigInteger;
    ProductIdInteger: BigInteger;
    PriceDecimal: Decimal;
    CompareAtPriceDecimal: Decimal;
    Sku: Text;
    ShopifyVariantesOriginal: Record "Shpfy Variant";
    NextPageUrl: Text;
    BaseUrl: Text;
    Shopify : Record "Shpfy Company";
    LastErr: HttpError;
begin
    ShopifyVariantRecord.DeleteAll();
    BaseUrl := 'https://shoptest.myshopify.com/admin/api/2024-04/variants.json';
    NextPageUrl := BaseUrl;

    // 初始化Shopify公司记录,确保获取有效Token
    if not Shopify.FindFirst() then begin
        Message('未找到有效的Shopify公司记录');
        exit;
    end;

    repeat
        // 每次循环创建新的请求对象,避免参数污染
        Clear(Request);
        Request.SetRequestUri(NextPageUrl);
        Request.Method := 'GET';
        
        Client.DefaultRequestHeaders.Clear();
        Client.DefaultRequestHeaders.Add('X-Shopify-Access-Token', Shopify.Token);

        if Client.Send(Request, Response) then begin
            Content := Response.Content();
            Content.ReadAs(JsonResponse);
            JsonObject.ReadFrom(JsonResponse);
            
            if JsonObject.Get('variants', JsonToken) then begin
                JsonArray := JsonToken.AsArray();
                foreach JsonToken in JsonArray do begin
                    if JsonToken.IsObject() then begin
                        VariantObject := JsonToken.AsObject();

                        // 解析Variant ID
                        if VariantObject.Get('id', TempToken) then begin
                            EVALUATE(VariantIdInteger, TempToken.AsValue().AsText());
                            VariantIdInteger := Max(VariantIdInteger, 0);
                        end else
                            VariantIdInteger := 0;

                        // 解析Product ID
                        if VariantObject.Get('product_id', TempToken) then begin
                            EVALUATE(ProductIdInteger, TempToken.AsValue().AsText());
                            ProductIdInteger := Max(ProductIdInteger, 0);
                        end else
                            ProductIdInteger := 0;

                        // 解析Price
                        if VariantObject.Get('price', TempToken) then begin
                            EVALUATE(PriceDecimal, TempToken.AsValue().AsText());
                            PriceDecimal := Max(PriceDecimal, 0);
                        end else
                            PriceDecimal := 0;

                        // 解析Compare At Price
                        CompareAtPriceDecimal := 0;
                        if VariantObject.Get('compare_at_price', TempToken) then begin
                            if not TempToken.AsValue().IsNull() then begin
                                EVALUATE(CompareAtPriceDecimal, TempToken.AsValue().AsText());
                                CompareAtPriceDecimal := Max(CompareAtPriceDecimal, 0);
                            end;
                        end;

                        // 解析SKU
                        Sku := '';
                        if VariantObject.Get('sku', TempToken) then
                            Sku := TempToken.AsValue().AsText();

                        // 插入记录(简化重复逻辑)
                        ShopifyVariantRecord.Init();
                        ShopifyVariantRecord.id := VariantIdInteger;
                        ShopifyVariantRecord.product_id := ProductIdInteger;
                        ShopifyVariantRecord.price := PriceDecimal;
                        ShopifyVariantRecord.compare_at_price := CompareAtPriceDecimal;
                        ShopifyVariantRecord.sku := Sku;
                        
                        // 匹配原变体记录
                        ShopifyVariantesOriginal.SetRange(SKU, Sku);
                        if ShopifyVariantesOriginal.FindFirst() then begin
                            ShopifyVariantRecord.Coincide := (VariantIdInteger = ShopifyVariantesOriginal.Id);
                            ShopifyVariantRecord."Id variante BC" := ShopifyVariantesOriginal.Id;
                        end else begin
                            ShopifyVariantRecord.Coincide := false;
                            ShopifyVariantRecord."Id variante BC" := 0;
                        end;
                        
                        ShopifyVariantRecord.Insert();
                    end;
                end;

                NextPageUrl := GetNextPageUrl(Response);
            end else begin
                Message('响应中未找到变体数据');
                NextPageUrl := '';
            end;
        end else begin
            LastErr := Client.LastError();
            Message('请求Shopify API失败: 状态码%1,错误信息:%2', Format(Response.HttpStatusCode), LastErr.Message);
            NextPageUrl := '';
        end;
    until NextPageUrl = '';
    
    Message('已保存%1条Shopify变体数据', ShopifyVariantRecord.Count());
end;

procedure GetNextPageUrl(Response: HttpResponseMessage): Text
var
    LinkHeaders: List of [Text];
    LinkSegments: List of [Text];
    Segment: Text;
    StartPos: Integer;
    EndPos: Integer;
begin
    if not Response.Headers.Contains('Link') then
        exit('');

    Response.Headers.GetValues('Link', LinkHeaders);
    foreach LinkHeaders do begin
        LinkSegments := LinkHeaders.Split(',');
        foreach Segment in LinkSegments do begin
            // 匹配rel="next"或rel='next'的格式
            if Segment.Contains('rel="next"') or Segment.Contains('rel=''next''') then begin
                StartPos := Segment.IndexOf('<') + 1;
                EndPos := Segment.IndexOf('>');
                if StartPos > 0 and EndPos > StartPos then
                    exit(Segment.Substring(StartPos, EndPos - StartPos));
            end;
        end;
    end;
    exit('');
end;

关键修复说明

  1. 请求对象重置:每次循环调用Clear(Request)创建新的请求实例,避免旧参数残留
  2. Token有效性保障:添加Shopify.FindFirst()确保获取有效的鉴权Token,这是状态0错误的常见原因
  3. Link Header解析优化:修正变量名冲突,兼容单双引号的rel格式,提升分页URL提取的稳定性
  4. 错误信息增强:捕获Client.LastError()获取详细错误描述,便于定位问题
  5. 代码简化:合并插入记录的重复逻辑,增加解析失败的默认值处理,提升代码健壮性

内容的提问来源于stack exchange,提问作者JulioSistemas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 14:24:55