放弃postman 拥抱.http

文摘   2024-11-05 08:22   湖北  

在日常开发中,我们经常需要测试 API 接口。虽然 Postman 等工具很强大,但频繁切换工具还是会影响开发效率。今天给大家介绍 IntelliJ IDEA 中一个强大但经常被忽视的功能 —— HTTP 请求文件(.http)。本文将从基础到进阶,全面介绍这个功能的使用方法。

一、快速入门

1.1 创建请求文件

在 IDEA 中创建 HTTP 请求文件非常简单:

  1. 1. 右键项目目录

  2. 2. 选择 New > HTTP Request

  3. 3. 输入文件名(例如 api-tests.http

1.2 第一个请求

### 获取用户列表
GET http://localhost:8080/api/users

### 创建新用户
POST http://localhost:8080/api/users
Content-Typeapplication/json

{
    "name": "张三",
    "email": "zhangsan@example.com",
    "age": 25
}

使用方法:

  • • 将光标放在请求上

  • • 按下 Ctrl + Enter(Windows/Linux)或 Cmd + Enter(Mac)

  • • 右侧窗口会显示响应结果

二、基础功能详解

2.1 HTTP 方法支持

### GET 请求
GET http://api.example.com/users/1

### POST 请求
POST http://api.example.com/users
Content-Typeapplication/json

{
    "name": "李四",
    "email": "lisi@example.com"
}

### PUT 请求
PUT http://api.example.com/users/1
Content-Typeapplication/json

{
    "name": "李四(已更新)"
}

### DELETE 请求
DELETE http://api.example.com/users/1

2.2 请求头设置

### 带认证的请求
GET http://api.example.com/secure-endpoint
AuthorizationBearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Acceptapplication/json
Content-Typeapplication/json

2.3 请求参数

### URL 参数
GET http://api.example.com/users?page=1&size=10&sort=name

### 路径参数
GET http://api.example.com/users/{userId}/orders/{orderId}

三、环境变量配置

3.1 创建环境配置文件

创建 http-client.env.json

{
    "dev": {
        "baseUrl": "http://localhost:8080",
        "token": "dev-token-123",
        "username": "dev-admin",
        "password": "dev-password"
    },
    "prod": {
        "baseUrl": "https://api.company.com",
        "token": "prod-token-456",
        "username": "prod-admin",
        "password": "prod-password"
    }
}

3.2 使用环境变量

### 使用环境变量的请求
GET {{baseUrl}}/api/users
AuthorizationBearer {{token}}

### 登录请求
POST {{baseUrl}}/api/login
Content-Typeapplication/json

{
    "username": "{{username}}",
    "password": "{{password}}"
}

3.3 私密信息配置

创建 http-client.private.env.json(注意加入 .gitignore):

{
    "dev": {
        "apiKey": "dev-key-123",
        "webhookSecret": "dev-webhook-secret"
    },
    "prod": {
        "apiKey": "prod-key-456",
        "webhookSecret": "prod-webhook-secret"
    }
}

四、高级功能与技巧

4.1 请求脚本

### 带验证脚本的请求
POST {{baseUrl}}/api/users
Content-Typeapplication/json

{
    "name": "测试用户",
    "email": "test@example.com"
}

> {%
    client.test("创建用户成功", function() {
        client.assert(response.status === 201);
        client.assert(response.body.id != null);
        client.global.set("userId", response.body.id);
    });
%}

4.2 文件上传

### 单文件上传
POST {{baseUrl}}/api/upload
Content-Typemultipart/form-data; boundary=WebAppBoundary

--WebAppBoundary
Content-Dispositionform-data; name="file"; filename="test.pdf"
Content-Typeapplication/pdf

< ./data/test.pdf
--WebAppBoundary--

### 多文件上传
POST {{baseUrl}}/api/upload-multiple
Content-Typemultipart/form-data; boundary=WebAppBoundary

--WebAppBoundary
Content-Dispositionform-data; name="files"; filename="file1.pdf"
Content-Typeapplication/pdf

< ./data/file1.pdf
--WebAppBoundary
Content-Dispositionform-data; name="files"; filename="file2.pdf"
Content-Typeapplication/pdf

< ./data/file2.pdf
--WebAppBoundary--

4.3 动态变量

### 使用动态变量
POST {{baseUrl}}/api/products
Content-Typeapplication/json

{
    "name": "商品{{$random.integer(1, 1000)}}",
    "price": {{$random.float(10, 1000)}},
    "sku": "SKU{{$random.alphanumeric(8)}}",
    "createTime": "{{$timestamp}}"
}

五、完整业务场景示例

5.1 用户注册登录流程

### 1. 注册
POST {{baseUrl}}/api/auth/register
Content-Typeapplication/json

{
    "username": "{{$random.alphabetic(8)}}",
    "email": "{{$random.email}}",
    "password": "{{$random.alphanumeric(12)}}"
}

> {%
    client.test("注册成功", function() {
        client.assert(response.status === 201);
        client.global.set("userId", response.body.id);
        client.global.set("userEmail", response.body.email);
    });
%}

### 2. 登录
POST {{baseUrl}}/api/auth/login
Content-Typeapplication/json

{
    "email": "{{userEmail}}",
    "password": "{{password}}"
}

> {%
    client.test("登录成功", function() {
        client.assert(response.status === 200);
        client.global.set("authToken", response.body.token);
    });
%}

5.2 电商下单流程

### 1. 检查商品库存
GET {{baseUrl}}/api/products/{{productId}}/stock

> {%
    client.test("库存检查", function() {
        client.assert(response.status === 200);
        client.assert(response.body.available > 0);
    });
%}

### 2. 加入购物车
POST {{baseUrl}}/api/cart/items
Content-Typeapplication/json
AuthorizationBearer {{authToken}}

{
    "productId": "{{productId}}",
    "quantity": 1
}

### 3. 查看购物车
GET {{baseUrl}}/api/cart
AuthorizationBearer {{authToken}}

### 4. 创建订单
POST {{baseUrl}}/api/orders
Content-Typeapplication/json
AuthorizationBearer {{authToken}}

{
    "cartId": "{{cartId}}",
    "addressId": "{{addressId}}",
    "couponCode": "SUMMER2024"
}

> {%
    client.test("订单创建成功", function() {
        client.assert(response.status === 201);
        client.global.set("orderId", response.body.orderId);
        client.global.set("orderAmount", response.body.totalAmount);
    });
%}

### 5. 支付订单
POST {{baseUrl}}/api/payments
Content-Typeapplication/json
AuthorizationBearer {{authToken}}

{
    "orderId": "{{orderId}}",
    "amount": {{orderAmount}},
    "method": "WECHAT"
}

六、调试与测试

6.1 响应断言

### 复杂响应断言
GET {{baseUrl}}/api/products

> {%
    client.test("产品列表检查", function() {
        // 状态码检查
        client.assert(response.status === 200);
        
        // 响应格式检查
        client.assert(Array.isArray(response.body));
        
        // 数据完整性检查
        response.body.forEach(function(product) {
            client.assert(product.id != null, "产品ID不能为空");
            client.assert(product.name != null, "产品名称不能为空");
            client.assert(product.price > 0, "产品价格必须大于0");
        });
        
        // 性能检查
        client.assert(response.responseTime < 1000, "响应时间超过1秒");
    });
%}

6.2 调试日志

### 调试信息打印
GET {{baseUrl}}/api/debug-test

> {%
    // 请求信息
    client.log("=== 请求信息 ===");
    client.log("URL: " + request.url);
    client.log("Method: " + request.method);
    client.log("Headers: " + JSON.stringify(request.headers));
    
    // 响应信息
    client.log("=== 响应信息 ===");
    client.log("Status: " + response.status);
    client.log("Headers: " + JSON.stringify(response.headers));
    
    // 响应体
    if (response.body) {
        client.log("Body: " + JSON.stringify(response.body, null, 2));
    }
    
    // 性能信息
    client.log("Response Time: " + response.responseTime + "ms");
%}

6.3 批量测试

### 批量请求测试
GET {{baseUrl}}/api/performance-test

> {%
    const startTime = new Date().getTime();
    
    // 发起多次请求
    for (let i = 0; i < 10; i++) {
        client.log(`发起第 ${i + 1} 次请求`);
        const response = client.execute();
        client.assert(response.status === 200);
    }
    
    const endTime = new Date().getTime();
    const duration = endTime - startTime;
    
    client.log(`总耗时: ${duration}ms`);
    client.log(`平均响应时间: ${duration / 10}ms`);
%}

HTTP 请求文件组织最佳实践

一、基本组织方式

1.1 使用标签组织

### @name userManagement
### @tags user, auth

### 1. 用户注册
POST {{baseUrl}}/api/users/register
Content-Typeapplication/json

{
    "username": "testuser",
    "email": "test@example.com"
}

### 2. 用户登录
# @name login
POST {{baseUrl}}/api/users/login
Content-Typeapplication/json

{
    "email": "test@example.com",
    "password": "password123"
}

> {%
    client.global.set("authToken", response.body.token)
%}

### 3. 获取用户信息
# @name getUserInfo
GET {{baseUrl}}/api/users/me
AuthorizationBearer {{authToken}}

1.2 按模块分文件

api-tests/
├── auth/
│   ├── login.http        # 认证相关请求
│   └── register.http     # 注册相关请求
├── users/
│   ├── profile.http      # 用户档案相关请求
│   └── settings.http     # 用户设置相关请求
├── products/
│   ├── catalog.http      # 商品目录相关请求
│   └── inventory.http    # 库存相关请求
├── orders/
│   ├── create.http       # 订单创建相关请求
│   └── payment.http      # 支付相关请求
├── http-client.env.json  # 环境配置
└── http-client.private.env.json  # 私密配置

二、实际示例

2.1 认证模块 (auth.http)

### @name authRequests
### @tags authentication

### 登录
# @name login
POST {{baseUrl}}/api/auth/login
Content-Typeapplication/json

{
    "email": "{{email}}",
    "password": "{{password}}"
}

> {%
    client.global.set("authToken", response.body.token)
%}

### 刷新Token
# @name refreshToken
POST {{baseUrl}}/api/auth/refresh
AuthorizationBearer {{authToken}}

### 登出
# @name logout
POST {{baseUrl}}/api/auth/logout
AuthorizationBearer {{authToken}}

2.2 用户模块 (users.http)

### @name userRequests
### @tags users

### 获取用户列表
# @name getUserList
GET {{baseUrl}}/api/users
AuthorizationBearer {{authToken}}

### 创建用户
# @name createUser
POST {{baseUrl}}/api/users
AuthorizationBearer {{authToken}}
Content-Typeapplication/json

{
    "name": "新用户",
    "email": "new@example.com",
    "role": "user"
}

### 更新用户信息
# @name updateUser
PUT {{baseUrl}}/api/users/{{userId}}
AuthorizationBearer {{authToken}}
Content-Typeapplication/json

{
    "name": "更新的名字"
}

2.3 商品模块 (products.http)

### @name productRequests
### @tags products

### 获取商品列表
# @name getProducts
GET {{baseUrl}}/api/products
AuthorizationBearer {{authToken}}

### 创建商品
# @name createProduct
POST {{baseUrl}}/api/products
AuthorizationBearer {{authToken}}
Content-Typeapplication/json

{
    "name": "新商品",
    "price": 99.99,
    "description": "商品描述"
}

### 更新商品
# @name updateProduct
PUT {{baseUrl}}/api/products/{{productId}}
AuthorizationBearer {{authToken}}
Content-Typeapplication/json

{
    "price": 88.88
}

三、高级组织技巧

3.1 使用请求变量

### 设置测试数据
# @name setupTestData
POST {{baseUrl}}/api/test-data
Content-Typeapplication/json

{
    "scenario": "user-flow"
}

> {%
    client.global.set("testUserId", response.body.userId)
    client.global.set("testOrderId", response.body.orderId)
%}

### 使用测试数据
GET {{baseUrl}}/api/users/{{testUserId}}/orders/{{testOrderId}}

3.2 测试场景组织

### @name e2eTestScenario
### @tags e2e, test

### 1. 创建测试用户
# @name createTestUser
POST {{baseUrl}}/api/users
Content-Typeapplication/json

{
    "name": "测试用户",
    "email": "test@example.com"
}

> {%
    client.global.set("userId", response.body.id)
%}

### 2. 创建测试订单
# @name createTestOrder
POST {{baseUrl}}/api/orders
Content-Typeapplication/json

{
    "userId": "{{userId}}",
    "items": [
        {
            "productId": "123",
            "quantity": 1
        }
    ]
}

> {%
    client.global.set("orderId", response.body.id)
%}

### 3. 清理测试数据
# @name cleanupTestData
DELETE {{baseUrl}}/api/test-data
Content-Typeapplication/json

{
    "userId": "{{userId}}",
    "orderId": "{{orderId}}"
}


字节笔记本
专注于科技领域的分享,AIGC,全栈开发,产品运营
 最新文章