Skip to content

发票查验SDK示例代码

注意事项

  1. appCode 需替换为您的实际授权码。
  2. apiPath 需要包含斜杠,例如 "/v1/check_zzs/info"

目录

Node.js

兼容性说明

  • Node.js 8+

示例代码

js
const axios = require('axios')

const API_BASE_URL = 'https://fpzwcx.com'
const APP_CODE = 'Your_AppCode'

const HEADERS = {
  'Content-Type': 'application/json',
  Authorization: `Bearer ${APP_CODE}`,
}

const requestCheckInvoice = async (apiPath, invoiceData) => {
  try {
    const response = await axios.post(
      `${API_BASE_URL}${apiPath}`,
      invoiceData,
      { headers: HEADERS }
    )
    const resultData = response.data

    if (resultData.code === 0) {
      console.log('✅ 查验成功:')
    } else {
      console.log('❌ 查验失败:')
    }
    console.log(resultData)
    return resultData
  } catch (error) {
    console.error('🚨 API 请求失败:', error.message)
    throw error
  }
}

// 示例发票数据
const invoiceData = {
  fpdm: '032002000113',
  fphm: '94468700',
  kprq: '20230310',
  bhsje: '3893.80',
  jym: '654321',
}

// 调用函数
requestCheckInvoice('/v1/check_zzs/info', invoiceData)

module.exports = requestCheckInvoice

使用步骤

1.安装依赖:

bash
npm install axios

2.替换 AppCode:

js
const APP_CODE = '获取的实际AppCode'

3.替换需要调用的接口路径(示例为增值税基础查验接口):

4.调用示例:

js
// 在异步上下文中调用
const result = await requestCheckInvoice('/v1/check_zzs/info', {
  fpdm: '032002000113',
  fphm: '94468700',
  // ...其他参数
})

Python

兼容性说明

  • Python ✅ 完全支持

示例代码

Python
import requests
import json

API_BASE_URL = 'https://fpzwcx.com'
APP_CODE = 'Your_AppCode'

HEADERS = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {}'.format(APP_CODE)
}

def request_check_invoice(apiPath, invoice_data):
    try:
        url = API_BASE_URL + apiPath
        response = requests.post(
            url,
            headers=HEADERS,
            json=invoice_data
        )
        response.raise_for_status()
        result_data = response.json()

        if result_data.get('code') == 0:
            print(u'✅ 查验成功:')
        else:
            print(u'❌ 查验失败:')
        print(json.dumps(result_data, indent=2, ensure_ascii=False))
        return result_data
    except requests.exceptions.RequestException as e:
        print(u'🚨 API 请求失败: {}'.format(str(e)))
        raise
    except ValueError as e:
        print(u'🚨 JSON 解析失败: {}'.format(str(e)))
        raise

if __name__ == '__main__':
    # 示例发票数据
    invoice_data = {
        "fpdm": "032002000113",
        "fphm": "94468700",
        "kprq": "20230310",
        "bhsje": "3893.80",
        "jym": "654321"
    }

    request_check_invoice('/v1/check_zzs/info', invoice_data)

使用步骤

1.安装依赖:

bash
pip install requests

2.替换 AppCode:

js
APP_CODE = 'your_appcode'

3.替换需要调用的接口路径(示例为增值税基础查验接口):

4.在代码中调用:

python

result = request_check_invoice('/v1/check_zzs/info', {
    "fpdm": "032002000113",
    "fphm": "94468700",
    # ...其他参数
})

或者直接执行脚本

bash
python invoice_check.py

Go

兼容性说明

  • Go 1.13+

示例代码

Go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

// 配置常量
const (
	DefaultAPIBASEURL = "https://fpzwcx.com"
	DefaultTimeout    = 30 * time.Second
)

// InvoiceClient 发票查验客户端
type InvoiceClient struct {
	apiBaseURL string
	appCode    string
	httpClient *http.Client
}

// NewInvoiceClient 创建新客户端
func NewInvoiceClient(appCode string, options ...ClientOption) *InvoiceClient {
	client := &InvoiceClient{
		apiBaseURL: DefaultAPIBASEURL,
		appCode:    appCode,
		httpClient: &http.Client{
			Timeout: DefaultTimeout,
		},
	}

	// 应用配置选项
	for _, opt := range options {
		opt(client)
	}
	return client
}

// ClientOption 客户端配置选项
type ClientOption func(*InvoiceClient)

// WithBaseURL 自定义API地址
func WithBaseURL(url string) ClientOption {
	return func(c *InvoiceClient) {
		c.apiBaseURL = url
	}
}

// WithTimeout 自定义超时时间
func WithTimeout(d time.Duration) ClientOption {
	return func(c *InvoiceClient) {
		c.httpClient.Timeout = d
	}
}

// CheckInvoiceResponse API响应结构
type CheckInvoiceResponse struct {
	Success   bool                   `json:"success"`   // 总体成功标志
	Code      int                    `json:"code"`     // 业务状态码
	Data      map[string]interface{} `json:"data"`     // 发票数据
	RequestID string                 `json:"requestId"` // 请求唯一标识
}

// CheckInvoice 发票查验方法
func (c *InvoiceClient) CheckInvoice(apiPath string, invoiceData map[string]interface{}) (*CheckInvoiceResponse, error) {
	// 构建完整URL
	url := c.apiBaseURL + apiPath

	// 序列化请求体
	jsonData, err := json.Marshal(invoiceData)
	if err != nil {
		return nil, fmt.Errorf("JSON序列化失败: %w", err)
	}

	// 创建请求对象
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+c.appCode)

	// 发送请求
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("API请求失败: %w", err)
	}
	defer resp.Body.Close()

	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		body, _ := ioutil.ReadAll(resp.Body)
		return nil, fmt.Errorf("HTTP错误: %s, 响应内容: %s", resp.Status, string(body))
	}

	// 解析响应体
	var result CheckInvoiceResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("JSON解析失败: %w", err)
	}

	// 检查业务状态码
	if !resp.Success {
        // 携带 RequestID 帮助追踪问题
        return resp, fmt.Errorf("业务异常 | requestId=%s | code=%d", resp.RequestID, resp.Code)
    }

	return &result, nil
}

func main() {
	// 初始化客户端
	client := NewInvoiceClient("Your_AppCode",
		WithBaseURL("https://fpzwcx.com"),
		WithTimeout(30*time.Second),
	)

	// 构造发票数据
	invoiceData := map[string]interface{}{
		"fpdm":  "032002000113",
		"fphm":  "94468700",
		"kprq":  "20230310",
		"bhsje": "3893.80",
		"jym":   "654321",
	}

	// 调用查验接口
	resp, err := client.CheckInvoice("/v1/check_zzs/info", invoiceData)
	if err != nil {
		fmt.Printf("🚨 查验失败: %v\n", err)
		return
	}

	// 处理成功响应
	fmt.Println("✅ 查验成功:")
	prettyResp, _ := json.MarshalIndent(resp, "", "  ")
	fmt.Println(string(prettyResp))
}

Java

兼容性说明

  • JDK 8 或以上版本
  • 需要支持 org.json 库(可使用 org.json:json 依赖)

示例代码

Java
package com.fpzwcx.sdk;

import org.json.JSONObject;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

/**
 * 增值税发票查验SDK
 * 支持三种调用方式:
 * 1. 静态快捷调用:InvoiceSDK.check("/path", data)
 * 2. 默认实例调用:new InvoiceSDK().requestCheckInvoice(...)
 * 3. 自定义配置调用:new InvoiceSDK(url, code).requestCheckInvoice(...)
 */

public class InvoiceSDK {
    private static final String DEFAULT_BASE_URL = "https://fpzwcx.com";
    private static final String DEFAULT_APP_CODE = "Your_AppCode";
    private static final int CONNECT_TIMEOUT = 10 * 1000;
    private static final int READ_TIMEOUT = 30 * 1000;

    private final String baseUrl;
    private final String appCode;

    // 静态快捷方法
    public static JSONObject check(String apiPath, JSONObject data) throws IOException {
        return new InvoiceSDK().requestCheckInvoice(apiPath, data);
    }

    // 全参数构造方法
    public InvoiceSDK(String baseUrl, String appCode) {
        this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
        this.appCode = appCode;
    }

    // 默认配置构造方法
    public InvoiceSDK() {
        this(DEFAULT_BASE_URL, DEFAULT_APP_CODE);
    }

    /**
     * 核心请求方法
     * @param apiPath API路径(需包含斜杠,如"/v1/check_zzs/info")
     * @param invoiceData 请求数据
     * @return 响应结果JSON对象
     */
    public JSONObject requestCheckInvoice(String apiPath, JSONObject invoiceData) throws IOException {
        HttpURLConnection connection = null;
        try {
            URL url = new URL(baseUrl + apiPath.replaceFirst("^/", ""));
            connection = (HttpURLConnection) url.openConnection();

            // 配置连接参数
            connection.setRequestMethod("POST");
            connection.setConnectTimeout(CONNECT_TIMEOUT);
            connection.setReadTimeout(READ_TIMEOUT);
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setRequestProperty("Authorization", "Bearer " + appCode);
            connection.setDoOutput(true);

            // 发送请求体
            try (OutputStream os = connection.getOutputStream()) {
                byte[] input = invoiceData.toString().getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
            }

            // 处理响应
            int status = connection.getResponseCode();
            if (status < 200 || status >= 300) {
                throw new IOException("HTTP Error: " + status + " - " + readErrorStream(connection));
            }

            String responseBody = readInputStream(connection.getInputStream());
            JSONObject result = new JSONObject(responseBody);
            handleResultStatus(result);
            return result;

        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    private String readInputStream(InputStream is) throws IOException {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(is, StandardCharsets.UTF_8))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        }
    }

    private String readErrorStream(HttpURLConnection conn) {
        try {
            InputStream es = conn.getErrorStream();
            return es != null ? readInputStream(es) : "No error body";
        } catch (IOException e) {
            return "Error reading error stream: " + e.getMessage();
        }
    }

    private void handleResultStatus(JSONObject result) {
        int code = result.optInt("code", -1);
        if (code == 0) {
            System.out.println("查验成功");
        } else {
            System.out.println("查验失败,错误码: " + code);
        }
        System.out.println(result.toString(2));  // 缩进格式化输出
    }

    /**
     * 直接运行示例(开发测试用)
     */
    public static void main(String[] args) {
        JSONObject sampleData = new JSONObject()
                .put("fpdm", "032002000113")
                .put("fphm", "94468700")
                .put("kprq", "20230310")
                .put("jshj", "3893.80")
                .put("jym", "");

        try {
            // 方式1:静态方法调用
            System.out.println("=== 静态方法调用示例 ===");
            JSONObject result1 = InvoiceSDK.check("/v1/check_zzs/info", sampleData);

            // 方式2:实例方法调用
            // System.out.println("\n=== 实例方法调用示例 ===");
            // JSONObject result2 = new InvoiceSDK().requestCheckInvoice("/v1/check_zzs/info", sampleData);

            // 方式3:自定义配置
            // System.out.println("\n=== 自定义配置调用示例 ===");
            // JSONObject result3 = new InvoiceSDK("https://fpzwcx.com", "Your_AppCode")
            //     .requestCheckInvoice("/v1/check_zzs/info", sampleData);

        } catch (IOException e) {
            System.err.println("示例执行失败: " + e.getMessage());
        }
    }
}

使用步骤

1.安装依赖 如果使用 Maven,请添加以下依赖:

xml
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20210307</version>
</dependency>

如果使用 Gradle,请添加以下依赖:

txt
dependencies {
    implementation 'org.json:json:20210307'
}

2.调用方式 SDK 提供三种调用方式:

  1. 静态快捷调用
    java
    JSONObject result = InvoiceSDK.check("/v1/check_zzs/info", data);
  2. 默认实例调用
    java
    InvoiceSDK sdk = new InvoiceSDK();
    JSONObject result = sdk.requestCheckInvoice("/v1/check_zzs/info", data);
  3. 自定义配置调用
    java
    InvoiceSDK sdk = new InvoiceSDK("https://fpzwcx.com", "Your_AppCode");
    JSONObject result = sdk.requestCheckInvoice("/v1/check_zzs/info", data);

可以直接运行 main 方法进行测试:

错误处理

  • 连接失败或超时会抛出 IOException
  • HTTP 状态码 400 以上时,会抛出 IOException,并包含错误信息。

C++

兼容性

  • C++11 及以上

示例代码

C++
#include <iostream>
#include <string>
#include <map>
#include <curl/curl.h>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

class InvoiceException : public std::exception {
public:
    InvoiceException(std::string msg, std::string reqId = "", int code = 0)
        : message_(std::move(msg)), requestId_(std::move(reqId)), code_(code) {}

    const char* what() const noexcept override {
        return message_.c_str();
    }

    std::string requestId() const { return requestId_; }
    int code() const { return code_; }

private:
    std::string message_;
    std::string requestId_;
    int code_;
};

class InvoiceClient {
public:
    InvoiceClient(const std::string& appCode,
                 const std::string& baseUrl = "https://fpzwcx.com",
                 long timeout = 30)
        : appCode_(appCode), baseUrl_(baseUrl), timeout_(timeout) {
        curl_global_init(CURL_GLOBAL_DEFAULT);
    }

    ~InvoiceClient() {
        curl_global_cleanup();
    }

    json checkInvoice(const std::string& apiPath, const json& invoiceData) {
        CURL* curl = curl_easy_init();
        if (!curl) throw InvoiceException("Failed to initialize cURL");

        std::string url = baseUrl_ + apiPath;
        struct curl_slist* headers = nullptr;
        headers = curl_slist_append(headers, "Content-Type: application/json");
        std::string authHeader = "Authorization: Bearer " + appCode_;
        headers = curl_slist_append(headers, authHeader.c_str());

        std::string responseStr;
        std::string requestBody = invoiceData.dump();

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestBody.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseStr);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_);

        CURLcode res = curl_easy_perform(curl);
        curl_slist_free_all(headers);

        if (res != CURLE_OK) {
            curl_easy_cleanup(curl);
            throw InvoiceException("HTTP request failed: " + std::string(curl_easy_strerror(res)));
        }

        long httpCode = 0;
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
        curl_easy_cleanup(curl);

        if (httpCode != 200) {
            throw InvoiceException("HTTP error: " + std::to_string(httpCode));
        }

        json responseJson;
        try {
            responseJson = json::parse(responseStr);
        } catch (json::parse_error& e) {
            throw InvoiceException("JSON parse failed: " + std::string(e.what()));
        }

        if (responseJson.find("success") == responseJson.end() ||
            responseJson.find("code") == responseJson.end() ||
            responseJson.find("requestId") == responseJson.end()) {
            throw InvoiceException("Invalid response structure");
        }

        if (!responseJson["success"].get<bool>()) {
            std::string reqId = responseJson.value("requestId", "");
            int code = responseJson["code"].get<int>();
            std::string msg = responseJson.find("message") != responseJson.end()
                            ? responseJson["message"].get<std::string>()
                            : "Unknown error";
            throw InvoiceException("Business error: " + msg, reqId, code);
        }

        return responseJson;
    }

private:
    static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
        size_t totalSize = size * nmemb;
        output->append(static_cast<char*>(contents), totalSize);
        return totalSize;
    }

    std::string appCode_;
    std::string baseUrl_;
    long timeout_;
};

int main() {
    try {
        InvoiceClient client("Your_AppCode");

        json invoiceData;
        invoiceData["fpdm"] = "032002000113";
        invoiceData["fphm"] = "94468700";
        invoiceData["kprq"] = "20230310";
        invoiceData["bhsje"] = "3893.80";
        invoiceData["jym"] = "654321";

        auto result = client.checkInvoice("/v1/check_zzs/info", invoiceData);

        std::cout << "✅ Check success (RequestID: "
                  << result["requestId"].get<std::string>() << ")\n";
        std::cout << result.dump(2) << std::endl;

    } catch (const InvoiceException& e) {
        std::cerr << "🚨 Error (" << e.code() << "): " << e.what();
        if (!e.requestId().empty()) {
            std::cerr << " [RequestID: " << e.requestId() << "]";
        }
        std::cerr << std::endl;
        return 1;
    }
    return 0;
}

使用步骤

  • 需要 libcurl
  • 需要 nlohmann/json 解析库

1.安装依赖

如果使用 vcpkg,可以安装:

sh
vcpkg install curl nlohmann-json

如果使用 CMake,请添加:

cmake
find_package(CURL REQUIRED)
find_package(nlohmann_json REQUIRED)

C#

兼容性

  1. 环境要求
  • .NET Core 3.1 及以上或 .NET 5+
  • 需要支持 System.Net.HttpSystem.Text.Json 命名空间
  1. 兼容性
  • Windows、Linux、macOS 皆可运行。
  • 适用于 .NET Framework 4.6.1+(需安装 System.Text.Json 兼容包)。

示例代码

C#
// .NET 6+
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class InvoiceApiException : Exception
{
    public string RequestId { get; }
    public int ErrorCode { get; }

    public InvoiceApiException(string message, string requestId = "", int errorCode = 0)
        : base(FormatMessage(message, requestId, errorCode))
    {
        RequestId = requestId;
        ErrorCode = errorCode;
    }

    private static string FormatMessage(string msg, string reqId, int code)
    {
        return $"[{reqId}] (Code: {code}) {msg}";
    }
}

public class InvoiceClient : IDisposable
{
    private readonly HttpClient _httpClient;
    private readonly string _appCode;

    public InvoiceClient(string appCode, string baseUrl = "https://fpzwcx.com", int timeoutSeconds = 30)
    {
        _appCode = appCode ?? throw new ArgumentNullException(nameof(appCode));

        _httpClient = new HttpClient
        {
            BaseAddress = new Uri(baseUrl),
            Timeout = TimeSpan.FromSeconds(timeoutSeconds)
        };

        _httpClient.DefaultRequestHeaders.Accept.Clear();
        _httpClient.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));
        _httpClient.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Bearer", _appCode);
    }

    public async Task<JsonDocument> CheckInvoiceAsync(string apiPath, object invoiceData)
    {
        try
        {
            // 序列化请求数据
            var jsonContent = JsonSerializer.Serialize(invoiceData);
            using var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

            // 发送请求
            var response = await _httpClient.PostAsync(apiPath, content);
            response.EnsureSuccessStatusCode(); // 检查HTTP状态码

            // 解析响应
            var responseStream = await response.Content.ReadAsStreamAsync();
            var jsonDoc = await JsonDocument.ParseAsync(responseStream);

            // 验证响应结构
            if (!jsonDoc.RootElement.TryGetProperty("success", out var successElem) ||
                !jsonDoc.RootElement.TryGetProperty("code", out var codeElem) ||
                !jsonDoc.RootElement.TryGetProperty("requestId", out var reqIdElem))
            {
                throw new InvoiceApiException("Invalid API response structure");
            }

            // 检查业务状态
            if (!successElem.GetBoolean())
            {
                var errorMsg = jsonDoc.RootElement.TryGetProperty("message", out var msgElem)
                    ? msgElem.GetString()
                    : "Unknown error";
                throw new InvoiceApiException(
                    $"Business error: {errorMsg}",
                    reqIdElem.GetString() ?? "",
                    codeElem.GetInt32()
                );
            }

            return jsonDoc;
        }
        catch (HttpRequestException ex)
        {
            throw new InvoiceApiException($"HTTP request failed: {ex.Message}");
        }
        catch (JsonException ex)
        {
            throw new InvoiceApiException($"JSON parse failed: {ex.Message}");
        }
    }

    public void Dispose()
    {
        _httpClient?.Dispose();
    }
}

// 使用示例
class Program
{
    static async Task Main(string[] args)
    {
        try
        {
            using var client = new InvoiceClient("Your_AppCode");

            var invoiceData = new
            {
                fpdm = "032002000113",
                fphm = "94468700",
                kprq = "20230310",
                bhsje = "3893.80",
                jym = "654321"
            };

            using var result = await client.CheckInvoiceAsync("/v1/check_zzs/info", invoiceData);

            Console.WriteLine("✅ 查验成功:");
            Console.WriteLine(JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true }));
        }
        catch (InvoiceApiException ex)
        {
            Console.WriteLine($"🚨 错误: {ex.Message}");
        }
    }
}

PHP

兼容性

  • PHP 5.6+

示例代码

PHP
<?php

class InvoiceApiClient {
    private $apiBaseUrl;
    private $appCode;
    private $timeout;
    private $verifySSL;

    /**
     * @param string $appCode    应用代码
     * @param string $apiBaseUrl API地址(默认:https://fpzwcx.com)
     * @param int    $timeout    超时时间(秒,默认30)
     * @param bool   $verifySSL  是否验证SSL证书
     */
    public function __construct($appCode, $apiBaseUrl = 'https://fpzwcx.com', $timeout = 30, $verifySSL = false) {
        $this->appCode = $appCode;
        $this->apiBaseUrl = rtrim($apiBaseUrl, '/');
        $this->timeout = $timeout;
        $this->verifySSL = $verifySSL; // 生产环境应启用SSL验证
    }

    /**
     * 执行发票查验
     * @param string $apiPath     API路径
     * @param array  $invoiceData 发票数据
     * @return array
     * @throws Exception
     */
    public function checkInvoice($apiPath, $invoiceData) {
        $url = $this->apiBaseUrl . $apiPath;
        $headers = [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->appCode
        ];

        // 发起请求
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_POSTFIELDS => json_encode($invoiceData),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => $this->timeout,
            CURLOPT_SSL_VERIFYPEER => $this->verifySSL, // 禁用SSL验证(仅测试用)
            CURLOPT_SSL_VERIFYHOST => $this->verifySSL ? 2 : 0
        ]);

        $response = curl_exec($ch);
        $error = curl_error($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        // 网络错误处理
        if ($error) {
            throw new Exception("API请求失败: " . $error);
        }

        // 解析JSON响应
        $result = json_decode($response, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new Exception("JSON解析失败: " . json_last_error_msg());
        }

        // 校验响应结构
        if (!isset($result['success'], $result['code'], $result['requestId'])) {
            throw new Exception("无效的API响应格式");
        }

        // 业务错误处理
        if (!$result['success']) {
            $message = isset($result['message']) ? $result['message'] : '未知错误';
            throw new Exception("业务异常: {$message} (Code: {$result['code']}, RequestID: {$result['requestId']})");
        }

        return $result;
    }
}

// 使用示例
try {
    // 创建客户端(测试时可临时禁用SSL验证)
    $client = new InvoiceApiClient(
        'Your_AppCode',
        'https://fpzwcx.com',
        30,
        false // 生产环境建议改为 true
    );

    $invoiceData = [
        "fpdm" => "032002000113",
        "fphm" => "94468700",
        "kprq" => "20230310",
        "bhsje" => "3893.80",
        "jym" => "654321"
    ];

    $result = $client->checkInvoice('/v1/check_zzs/info', $invoiceData);

    echo "✅ 查验成功 (RequestID: {$result['requestId']}):\n";
    print_r($result);

} catch (Exception $e) {
    echo "🚨 错误: " . $e->getMessage();
}
?>