# Java调用Mefree.NET API

本指南详细介绍如何使用 **Java** 实现对 Mefree.NET API 的调用，包括生成签名的方法、构建 HTTP 请求以及完整的调用流程。

***

#### **1. 签名规则概述**

Mefree.NET API 使用签名机制对请求进行身份验证。以下是签名的详细规则：

**1.1 签名字符串规则**

签名生成的格式如下：

```
sign = timestamp + method + requestPath
```

* **timestamp**：UTC 时间，格式为 ISO 8601，例如：`2024-11-26T12:34:56.789Z`。
* **method**：HTTP 方法，例如 `GET` 或 `POST`。
* **requestPath**：API 请求路径（包括查询参数），例如：
  * `/api/config`
  * `/api/order?quantity=65000&target_address=TRON_ADDRESS&period=1`

**1.2 签名生成流程**

1. 拼接签名字符串，格式为 `timestamp + method + requestPath`。
2. 使用 **HMAC-SHA256** 算法，用 API 的 **Secret Key** 对拼接的字符串进行加密。
3. 对加密结果进行 **Base64** 编码，生成最终的签名。

**1.3 请求头参数**

每次请求需要包含以下 HTTP 头：

* `Content-Type: application/json`
* `MF-ACCESS-KEY`: 您的 API Key。
* `MF-ACCESS-SIGN`: 生成的签名值。
* `MF-ACCESS-TIMESTAMP`: 当前的 UTC 时间戳。

***

#### **2. Java实现签名方法**

**2.1 签名生成函数**

以下代码展示了如何用 Java 生成 API 的签名：

```java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class MefreeApiUtils {
    /**
     * 生成 Mefree API 的签名
     * @param timestamp UTC 时间戳 (ISO 8601 格式)
     * @param method HTTP 方法 (GET/POST)
     * @param requestPath API 请求路径（含参数）
     * @param secretKey API 的 Secret Key
     * @return 签名字符串 (Base64 编码)
     * @throws Exception
     */
    public static String generateSignature(String timestamp, String method, String requestPath, String secretKey) throws Exception {
        // 拼接待签名字符串
        String stringToSign = timestamp + method + requestPath;

        // 使用 HMAC-SHA256 生成签名
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secretKeySpec);

        // 加密并进行 Base64 编码
        byte[] hash = sha256_HMAC.doFinal(stringToSign.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(hash);
    }
}
```

***

#### **3. API 请求构建**

**3.1 基础配置**

在 Java 项目中，定义以下常量用于配置 API 的基础信息：

```java
// Mefree API 配置信息
public class Config {
    public static final String BASE_URL = "https://api.mefree.net"; // Mefree API 基础地址
    public static final String API_KEY = "your_api_key";       // 替换为实际的 API Key
    public static final String SECRET_KEY = "your_secret_key"; // 替换为实际的 Secret Key
}
```

**3.2 通用请求方法**

使用 **HttpURLConnection** 构建通用的 HTTP 请求方法：

```java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpRequestUtil {
    /**
     * 发起 API 请求
     * @param method HTTP 方法 (GET/POST)
     * @param requestPath API 请求路径（含参数）
     * @param apiKey API Key
     * @param secretKey Secret Key
     * @return 响应内容
     * @throws Exception
     */
    public static String sendRequest(String method, String requestPath, String apiKey, String secretKey) throws Exception {
        // 当前 UTC 时间戳
        String timestamp = java.time.Instant.now().toString();

        // 生成签名
        String signature = MefreeApiUtils.generateSignature(timestamp, method, requestPath, secretKey);

        // 构造 URL
        URL url = new URL(Config.BASE_URL + requestPath);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        // 设置请求方法和头信息
        conn.setRequestMethod(method);
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestProperty("MF-ACCESS-KEY", apiKey);
        conn.setRequestProperty("MF-ACCESS-SIGN", signature);
        conn.setRequestProperty("MF-ACCESS-TIMESTAMP", timestamp);


        // 读取响应
        int responseCode = conn.getResponseCode();
        BufferedReader br = new BufferedReader(new InputStreamReader(
                (responseCode < 400) ? conn.getInputStream() : conn.getErrorStream()
        ));

        StringBuilder response = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            response.append(line);
        }
        br.close();

        return response.toString();
    }
}
```

***

#### **4. 示例接口调用**

**4.1 获取账户信息**

**接口描述**：

* 请求路径：`/api/config`
* HTTP 方法：`GET`

**调用代码**：

```java
public class Main {
    public static void main(String[] args) {
        try {
            String response = HttpRequestUtil.sendRequest("GET", "/api/config", Config.API_KEY, Config.SECRET_KEY);
            System.out.println("账户信息: " + response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

***

**4.2 创建订单**

**接口描述**：

* 请求路径：`/api/order?quantity=65000&target_address=TRON_ADDRESS&period=1`
* HTTP 方法：`POST`

**调用代码**：

```java
public class Main {
    public static void main(String[] args) {
        try {
            String requestPath = "/api/order?quantity=65000&target_address=TRON_ADDRESS&period=1";
            String response = HttpRequestUtil.sendRequest("POST", requestPath, Config.API_KEY, Config.SECRET_KEY);
            System.out.println("订单已创建: " + response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

***

**4.3 查询订单状态**

**接口描述**：

* 请求路径：`/api/order/{pay_hash}`
* HTTP 方法：`GET`

**调用代码**：

```java
public class Main {
    public static void main(String[] args) {
        try {
            String payHash = "abcd1234"; // 替换为实际的 pay_hash
            String requestPath = "/api/order/" + payHash;
            String response = HttpRequestUtil.sendRequest("GET", requestPath, Config.API_KEY, Config.SECRET_KEY);
            System.out.println("订单状态: " + response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

***

#### **5. 常见问题**

**5.1 签名无效 (401 Unauthorized)**

* 确认 `MF-ACCESS-KEY` 是否正确。
* 确保签名按照规则生成：
  * 拼接顺序为：`timestamp + method + requestPath`。
  * 时间戳格式是否为 UTC。
  * 使用正确的 `SECRET_KEY`。

**5.2 请求参数错误 (400 Bad Request)**

* 检查请求路径是否正确，尤其是查询参数是否完整。
* 确认 `Content-Type` 是否为 `application/json`。

**5.3 请求频率限制 (429 Too Many Requests)**

* 添加合理的请求间隔（例如每秒最多 2 次请求）。

***

#### **6. 总结**

通过本指南，您可以使用 Java 实现对 Mefree.NET API 的调用，包括生成签名、发送请求和解析响应数据。对重要的操作（如订单创建）建议添加重试机制，确保请求可靠性。如遇问题，请联系 Mefree 官方支持团队。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mefree.net/zh/getting-started/how-to-buy-energy/java.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
