一、http请求和响应报文

1.1 http请求报文

一个http请求报文由四部分组成,按顺序排列为请求行(Request Line)、请求头(Request Headers)、空行(Blank Line)、请求体(Request Body)。前三个是必须的,请求体可选(GET没有,POST/PUT可能有)。请求行格式为(为换行,下同):
<方法> <请求URL> <HTTP版本>
请求头格式:
<字段名>: <值>
请求体格式可以是JSON、传统web表单数据、xml、纯文本、二进制数据(如zip文件、图片)。
例如,JSON格式

POST /api/users HTTP/1.1
Content-Type: application/json
Content-Length: 45

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

传统web表单数据:

POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 29

username=admin&password=123456

一个GET报文示例:

GET /api/users/123/posts?page=2&size=10 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0
Accept: application/json
Accept-Language: zh-CN
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Cache-Control: no-cache

← 空行(没有请求体)

补充:请求参数说明

在平时的实践中,可以看到http请求携带的数据有两个地方,一个是URL查询参数(?后的内容),一个请求体(Request Body)的内容。
例如,对于一个查询请求https://api.example.com/users?page=1&size=10&sort=name,请求报文是这这样的:

GET /users?page=1&size=10&sort=name HTTP/1.1   ← 参数在这里!
Host: api.example.com
User-Agent: Mozilla/5.0
Accept: application/json

← 空行(GET请求通常没有请求体)

“url中?后的内容”与请求体不冲突,都可以有:

POST /api/orders?coupon=SAVE10 HTTP/1.1
Host: example.com
Content-Type: application/json

{
    "productId": 123,
    "quantity": 2,
    "address": "北京"
}

另外还有一种RESTful API(例如https://api.example.com/users/123/posts/456)中的路径参数(Path Parameters)又不一样,它既不进查询字符串,也不进请求体。

GET /users/123/posts/456 HTTP/1.1
         ↑        ↑
      用户ID    帖子ID

1.2 响应报文

一个标准的HTTP响应由四部分组成,按顺序为状态行、响应头、空行、响应体。
状态行内容为HTTP版本、状态码、状态描述。响应头是键值对、响应体是需要获取的返回数据。

一个例子:

HTTP/1.1 200 OK                    ← 状态行 (Status Line)
Content-Type: application/json     ← 响应头 (Headers)
Content-Length: 35                 ← 响应头
                                   ← 空行 (CRLF) 分隔头与体
{"name":"John","age":30}           ← 响应体 (Body) —— 你的数据在这里

二、HTTP请求与响应的java代码

2.1 发送请求

用原生代码构建(写法不唯一):

URL url = new URL("https://api.example.com/users");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

// 1. 设置请求行中的方法
conn.setRequestMethod("POST");

// 2. 设置请求头
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "Bearer token123");
conn.setRequestProperty("User-Agent", "MyApp/1.0");

// 3. 发送请求体(如果有)
conn.setDoOutput(true);
String requestBody = "{\"name\":\"张三\"}";
try(OutputStream os = conn.getOutputStream()) {
    os.write(requestBody.getBytes(StandardCharsets.UTF_8));
}

// 4. 发送后,实际报文是:
// POST /users HTTP/1.1
// Host: api.example.com
// Content-Type: application/json
// Authorization: Bearer token123
// User-Agent: MyApp/1.0
// Content-Length: 15
// 
// {"name":"张三"}

2.2 接收请求

URL中的?参数 → @RequestParam 或 request.getParameter()
URL路径中的变量 → @PathVariable
请求体中的数据 → @RequestBody 或 request.getInputStream()

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    // 1. 路径参数 - 来自URL路径
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        // id = 123(来自 /api/users/123)
        return userService.findById(id);
    }
    
    // 2. 查询参数 - 来自?之后
    @GetMapping
    public List<User> getUsers(@RequestParam(defaultValue="1") int page,
                               @RequestParam(defaultValue="10") int size) {
        // page=1, size=10(来自 /api/users?page=1&size=10)
        return userService.findByPage(page, size);
    }
    
    // 3. 请求体 - 来自HTTP Body
    @PostMapping
    public User createUser(@RequestBody User user) {
        // user对象的数据来自请求体中的JSON
        return userService.create(user);
    }
    
    // 混合使用
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, 
                          @RequestBody User user) {
        // id来自路径参数,user数据来自请求体
        return userService.update(id, user);
    }
}

更多推荐