解锁HTTP方法奥秘:GET与POST的深度探索与实战演示

目录

[一、HTTP 常见方法概述](#一、HTTP 常见方法概述)

[二、GET 方法和 POST 方法深入剖析](#二、GET 方法和 POST 方法深入剖析)

1、基本用途

2、传参方式

[GET 方法](#GET 方法)

[POST 方法](#POST 方法)

3、参数容量与私密性

参数容量

私密性

[三、Postman 演示 GET 和 POST 的区别](#三、Postman 演示 GET 和 POST 的区别)

1、Postman平台介绍

[2、GET 方法演示](#2、GET 方法演示)

参数设置

服务器接收情况

[3、POST 方法演示](#3、POST 方法演示)

参数设置

服务器接收情况

[四、TCP 套接字演示 GET 和 POST 的区别](#四、TCP 套接字演示 GET 和 POST 的区别)

[1、GET 方法提交](#1、GET 方法提交)

[HTML 表单设置 和 服务端的更改](#HTML 表单设置 和 服务端的更改)

浏览器访问与参数提交

[2、POST 方法提交](#2、POST 方法提交)

3、注意事项

数据敏感性

五、HTTP常见方法

[1、GET 方法(重点)](#1、GET 方法(重点))

[2、POST 方法(重点)](#2、POST 方法(重点))

[3、PUT 方法(不常用)](#3、PUT 方法(不常用))

[4、HEAD 方法](#4、HEAD 方法)

[5、DELETE 方法(不常用)](#5、DELETE 方法(不常用))

[6、OPTIONS 方法](#6、OPTIONS 方法)

[7、其他 HTTP 方法](#7、其他 HTTP 方法)

[TRACE 方法](#TRACE 方法)

[CONNECT 方法](#CONNECT 方法)

[PATCH 方法](#PATCH 方法)

8、方法特性总结

9、实际应用建议


一、HTTP 常见方法概述

HTTP(Hypertext Transfer Protocol,超文本传输协议)定义了一组请求方法,用于指示对服务器上资源执行的操作类型。这些方法为客户端与服务器之间的交互提供了标准化的方式。

方法 说明 支持的 HTTP 协议版本
GET 用于从服务器获取指定资源的信息。它是一种幂等操作,即多次执行相同请求不会对服务器上的资源产生额外影响。 1.0、1.1
POST 主要用于向服务器提交数据,通常用于创建新资源或触发服务器上的某些处理逻辑。POST 请求不是幂等的,多次执行可能会创建多个相同或不同的资源。 1.0、1.1
PUT 用于将实体主体(数据)传输到服务器上的指定位置,以替换该位置现有的资源。如果资源不存在,则创建新资源。PUT 请求是幂等的。 1.0、1.1
HEAD 与 GET 方法类似,但只返回响应报文的首部,而不返回实际资源内容。常用于检查资源是否存在、获取资源的元信息等。 1.0、1.1
DELETE 用于请求服务器删除指定位置的资源。DELETE 请求是幂等的。 1.0、1.1
OPTIONS 用于询问服务器支持哪些 HTTP 方法,以及服务器对特定资源的支持选项。常用于跨域请求前的预检请求。 1.1
TRACE 用于沿着请求 - 响应链追踪请求的路径,主要用于测试和诊断目的。不过,由于存在安全风险(如 XST 攻击),现在很少使用。 1.1
CONNECT 要求服务器使用隧道协议(如 SSL/TLS)连接代理,通常用于建立 HTTPS 连接时的隧道。 1.1
LINK 用于建立当前资源与另一个资源之间的联系,定义资源之间的关系。不过,该方法在实际应用中较少使用。 1.0
UNLINK 用于断开当前资源与另一个资源之间的连接关系。同样,在实际应用中较少使用。 1.0

在实际应用中,最常用的 HTTP 方法是 GET 方法和 POST 方法,下面将重点对这两种方法进行详细讲解。


二、GET 方法和 POST 方法深入剖析

1、基本用途

  • GET 方法:一般用于从服务器获取某种资源信息。例如,在浏览器中输入一个网址,浏览器就会使用 GET 方法向服务器请求该网址对应的网页内容。

  • POST 方法:一般用于将数据上传给服务器。比如,在登录表单中填写用户名和密码并提交,就是使用 POST 方法将用户输入的数据发送给服务器进行验证。

虽然通常按照上述方式使用,但实际开发中也有特殊情况。例如,百度搜索在提交搜索关键词时,实际使用的是 GET 方法。这是因为搜索操作主要是获取与关键词相关的搜索结果,符合 GET 方法获取资源的本质,而且 GET 方法便于用户分享包含特定关键词的搜索链接。

2、传参方式

GET 方法

  • 通过 URL 传参。

  • 参数会附加在 URL 后面,以 ? 开头,多个参数之间用 & 连接。

  • 例如:https://www.example.com/search?keyword=apple&page=1,其中 keyword=applepage=1 就是通过 URL 传递的参数。

POST 方法

  • 通过请求正文传参。

  • 参数包含在 HTTP 请求的正文部分,不会显示在 URL 中。

  • 例如,在登录表单提交时,用户名和密码等数据会被封装在请求正文中发送给服务器。

3、参数容量与私密性

参数容量

  • 由于 URL 的长度是有限制的(不同浏览器和服务器对 URL 长度的限制有所不同,但通常不会太长),所以 GET 方法通过 URL 传参能携带的数据量相对较少。

  • 而 POST 方法通过正文传参,理论上可以携带更多的数据,不受 URL 长度的限制。

私密性

  • POST 方法传参更加私密。

  • 因为 POST 方法不会将参数回显到 URL 当中,所以其他人不容易通过查看 URL 来获取传递的参数。

  • 然而,不能因此就认为 POST 方法比 GET 方法更安全。

  • 实际上,GET 方法和 POST 方法在传输数据时默认都是明文传送,都存在安全风险。要确保数据传输的安全性,只能通过加密技术(如 HTTPS 协议,它使用 SSL/TLS 协议对数据进行加密传输)来完成。


三、Postman 演示 GET 和 POST 的区别

Postman 是一款常用的 API 开发和测试工具,下面通过 Postman 来演示 GET 和 POST 方法在传参方面的区别。

1、Postman平台介绍

Postman 是一个用于API开发和测试的协作平台,主要功能包括:

  • API请求构建与发送:支持HTTP/HTTPS请求(GET、POST等),可自定义请求头、参数、Body等。

  • 自动化测试:支持编写测试脚本验证响应结果。

  • 团队协作:可共享API集合、环境变量等。

  • 文档生成:自动根据请求生成API文档。

  • Mock服务器:模拟API响应进行前端开发。

2、GET 方法演示

参数设置

当使用 GET 方法访问服务器时,应该在 URL 中进行传参。在 Postman 中,可以在 "Params" 选项卡下进行参数设置。设置参数时,可以看到对应的 URL 会随之变化,参数会自动附加到 URL 后面。

例如,设置参数 a=1&b=2,URL 会变成类似 https://yourserver.com/api?a=1&b=2 的形式。

服务器接收情况

此时在服务器收到的 HTTP 请求中,可以在请求行中的 URL 里看到我们刚才在 Postman 中设置的参数。这表明 GET 方法确实是通过 URL 来传递参数的。

3、POST 方法演示

参数设置

如果使用 POST 方法,则应该通过请求正文进行传参。在 Postman 中,可以在 "Body" 选项卡下进行参数设置。可以选择 "raw" 方式传参,"raw" 表示原始传参,即输入的参数是什么样,实际传递的参数就是什么样。

例如,可以输入 JSON 格式的数据 {"name": "John", "age": 25} 作为参数。

服务器接收情况

此时服务器收到的 HTTP 请求的请求正文就不再是空字符串,而是我们通过正文传递的参数。同时,由于响应正文不为空字符串,响应报头当中会出现 "Content - Length" 属性,该属性表示响应正文的长度。如下:


四、TCP 套接字演示 GET 和 POST 的区别

为了更直观地演示 GET 方法和 POST 方法传参的区别,我们可以通过编写简单的 HTML 表单和服务器端代码,利用 TCP 套接字来实现浏览器提交参数的功能。

1、GET 方法提交

HTML 表单设置 和 服务端的更改

index.html 文件中加入两个表单,用于用户输入用户名和密码,并新增一个提交按钮。表单中可以通过修改 method 属性来指定参数提交的方法(GET 或 POST),还有一个 action 属性,表示想把这个表单提交给服务器上的哪个资源(通常是一个服务器端处理程序的文件路径)。示例代码如下:

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>HTTP Server Test</title>
</head>
<body>
    <h1>Hello HTTP Server</h1>
    
    <h2>GET 表单提交测试</h2>
    <form method="GET" action="/">
        User name:<br>
        <input type="text" name="username" placeholder="Enter username">
        <br><br>
        User password:<br>
        <input type="password" name="psw" placeholder="Enter password">
        <br><br>
        <input type="submit" value="Submit">
    </form>
    
    <hr>
    
    <h3>调试信息:</h3>
    <p>提交表单后,查看服务器控制台输出的请求信息</p>
    <p>提交后URL会变成: http://your-ip:8080/?username=xxx&psw=yyy</p>
    
    <script>
        // 显示当前URL
        document.write('<p>当前URL: ' + window.location.href + '</p>');
        document.write('<p>表单提交后,请注意查看服务器控制台的输出</p>');
    </script>
</body>
</html>

method="GET":指定表单提交方式

  • GET:数据通过URL参数传递(?name=value&...

  • POST:数据通过请求体传递(更安全,适合敏感信息)

action="/":指定表单提交的目标URL

  • /:提交到当前服务器的根路径

  • 如果为空"",则提交到当前页面

同时更新一下服务端的代码,如下:

cpp 复制代码
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;

int main()
{
    // 创建套接字
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0) {
        cerr << "socket error!" << endl;
        return 1;
    }
    
    // 绑定
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(8080);
    local.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0) {
        cerr << "bind error!" << endl;
        return 2;
    }
    
    // 监听
    if (listen(listen_sock, 5) < 0) {
        cerr << "listen error!" << endl;
        return 3;
    }
    
    cout << "Server started on port 8080..." << endl;
    
    // 启动服务器
    for (;;) {
        struct sockaddr_in peer;
        memset(&peer, 0, sizeof(peer));
        socklen_t len = sizeof(peer);
        
        int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);
        if (sock < 0) {
            cerr << "accept error!" << endl;
            continue;
        }
        
        // 输出客户端信息
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &peer.sin_addr, client_ip, sizeof(client_ip));
        cout << "Connection from: " << client_ip << ":" << ntohs(peer.sin_port) << endl;
        
        if (fork() == 0) { // 子进程
            close(listen_sock);
            
            // 读取HTTP请求
            char buffer[4096] = {0};
            int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0);
            
            if (bytes_received > 0) {
                buffer[bytes_received] = '\0';
                cout << "--------------------------http request begin--------------------------" << endl;
                cout << buffer;
                cout << "---------------------------http request end---------------------------" << endl;
                
                // 解析请求方法
                string request(buffer);
                size_t method_end = request.find(' ');
                string method = request.substr(0, method_end);
                
                // 解析请求路径
                size_t path_start = method_end + 1;
                size_t path_end = request.find(' ', path_start);
                string path = request.substr(path_start, path_end - path_start);
                
                cout << "Method: " << method << endl;
                cout << "Path: " << path << endl;
                
                // 如果是根路径或表单提交路径,返回HTML
                if (path == "/" || path.find('/') == 0) {
                    // 读取HTML文件
                    ifstream in("index.html", ios::binary); // 以二进制模式打开
                    if (in.is_open()) {
                        in.seekg(0, ios::end);
                        int file_size = in.tellg();
                        in.seekg(0, ios::beg);
                        
                        char* file_content = new char[file_size + 1];
                        in.read(file_content, file_size);
                        file_content[file_size] = '\0';
                        in.close();
                        
                        // 构建HTTP响应(正确的HTTP格式)
                        string response = "HTTP/1.1 200 OK\r\n";
                        response += "Content-Type: text/html; charset=UTF-8\r\n"; // 添加字符集
                        response += "Content-Length: " + to_string(file_size) + "\r\n";
                        response += "Connection: close\r\n";
                        response += "\r\n";  // 空行,分隔头部和正文
                        response += string(file_content, file_size);
                        
                        send(sock, response.c_str(), response.size(), 0);
                        delete[] file_content;
                    } else {
                        // 404 Not Found
                        string response = "HTTP/1.1 404 Not Found\r\n";
                        response += "Content-Type: text/html; charset=UTF-8\r\n";
                        response += "\r\n";
                        response += "<html><body><h1>404 Not Found</h1></body></html>";
                        send(sock, response.c_str(), response.size(), 0);
                    }
                }
            }
            
            close(sock);
            exit(0);
        }
        
        close(sock);
        waitpid(-1, nullptr, WNOHANG); // 非阻塞等待子进程
    }
    
    close(listen_sock);
    return 0;
}

此时我们跑起来服务端,然后在浏览器上请求访问服务端:

浏览器访问与参数提交

  • 当用浏览器访问服务器时,会显示上述两个表单。

  • 如果选择使用 GET 方法提交参数,填充完用户名和密码并点击提交按钮后,用户名和密码会自动同步到 URL 当中。

  • 例如,URL 可能变成 https://yourserver.com/submit?username=John&password=123456

  • 同时,在服务器端可以通过解析 URL 来获取刚才在浏览器提交的参数。

2、POST 方法提交

同上,为了方便测试,我们修改一下相关的代码:

index.html

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>HTTP Server Test</title>
</head>
<body>
    <h1>Hello HTTP Server</h1>
    
    <h2>POST 表单提交测试</h2>
    <form method="POST" action="/">
        User name:<br>
        <input type="text" name="username" placeholder="Enter username">
        <br><br>
        User password:<br>
        <input type="password" name="psw" placeholder="Enter password">
        <br><br>
        <input type="submit" value="Submit">
    </form>
    
    <hr>
    
    <h3>调试信息:</h3>
    <p>提交表单后,查看服务器控制台输出的请求信息和POST数据</p>
    <p>注意:POST提交后URL不会变化,数据在请求体中</p>
    
    <script>
        // 显示当前URL
        document.write('<p>当前URL: ' + window.location.href + '</p>');
        document.write('<p>使用POST方法提交,数据不会显示在URL中</p>');
    </script>
</body>
</html>

server.cpp

cpp 复制代码
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sstream>
#include <vector>
using namespace std;

// 解析POST数据
string parsePostData(const string& request) {
    size_t header_end = request.find("\r\n\r\n");
    if (header_end == string::npos) {
        return "";
    }
    
    string body = request.substr(header_end + 4);
    
    // 查找Content-Length
    size_t content_length_pos = request.find("Content-Length: ");
    if (content_length_pos == string::npos) {
        return "";
    }
    
    size_t content_length_end = request.find("\r\n", content_length_pos);
    string content_length_str = request.substr(content_length_pos + 16, 
                                              content_length_end - content_length_pos - 16);
    
    int content_length = stoi(content_length_str);
    
    // 确保我们有完整的body
    if (body.length() < (size_t)content_length) {
        return "";
    }
    
    body = body.substr(0, content_length);
    return body;
}

// 解析查询字符串(用于GET和POST的body)
void parseQueryString(const string& query, vector<pair<string, string>>& params) {
    size_t start = 0;
    while (start < query.length()) {
        size_t end = query.find('&', start);
        if (end == string::npos) {
            end = query.length();
        }
        
        string param = query.substr(start, end - start);
        size_t equal_pos = param.find('=');
        
        if (equal_pos != string::npos) {
            string key = param.substr(0, equal_pos);
            string value = param.substr(equal_pos + 1);
            params.push_back(make_pair(key, value));
        }
        
        start = end + 1;
    }
}

int main()
{
    // 创建套接字
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0) {
        cerr << "socket error!" << endl;
        return 1;
    }
    
    // 设置SO_REUSEADDR选项,避免"Address already in use"错误
    int opt = 1;
    if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        cerr << "setsockopt error!" << endl;
        return 1;
    }
    
    // 绑定
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(8080);
    local.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0) {
        cerr << "bind error!" << endl;
        return 2;
    }
    
    // 监听
    if (listen(listen_sock, 5) < 0) {
        cerr << "listen error!" << endl;
        return 3;
    }
    
    cout << "Server started on port 8080..." << endl;
    cout << "Visit http://localhost:8080 in your browser" << endl;
    
    // 启动服务器
    for (;;) {
        struct sockaddr_in peer;
        memset(&peer, 0, sizeof(peer));
        socklen_t len = sizeof(peer);
        
        int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);
        if (sock < 0) {
            cerr << "accept error!" << endl;
            continue;
        }
        
        // 输出客户端信息
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &peer.sin_addr, client_ip, sizeof(client_ip));
        cout << "\nConnection from: " << client_ip << ":" << ntohs(peer.sin_port) << endl;
        
        if (fork() == 0) { // 子进程
            close(listen_sock);
            
            // 读取HTTP请求
            char buffer[8192] = {0};  // 增加缓冲区大小以容纳POST数据
            int bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0);
            
            if (bytes_received > 0) {
                buffer[bytes_received] = '\0';
                cout << "--------------------------http request begin--------------------------" << endl;
                cout << buffer;
                cout << "---------------------------http request end---------------------------" << endl;
                
                // 解析请求方法
                string request(buffer);
                size_t method_end = request.find(' ');
                string method = request.substr(0, method_end);
                
                // 解析请求路径
                size_t path_start = method_end + 1;
                size_t path_end = request.find(' ', path_start);
                string path = request.substr(path_start, path_end - path_start);
                
                cout << "Method: " << method << endl;
                cout << "Path: " << path << endl;
                
                // 解析POST数据
                if (method == "POST") {
                    string postData = parsePostData(request);
                    if (!postData.empty()) {
                        cout << "POST Data: " << postData << endl;
                        
                        // 解析POST参数
                        vector<pair<string, string>> params;
                        parseQueryString(postData, params);
                        
                        cout << "Parsed POST parameters:" << endl;
                        for (const auto& param : params) {
                            cout << "  " << param.first << " = " << param.second << endl;
                        }
                    }
                }
                // 解析GET参数
                else if (method == "GET") {
                    size_t query_start = path.find('?');
                    if (query_start != string::npos) {
                        string query = path.substr(query_start + 1);
                        path = path.substr(0, query_start);
                        
                        cout << "GET Query: " << query << endl;
                        
                        // 解析GET参数
                        vector<pair<string, string>> params;
                        parseQueryString(query, params);
                        
                        cout << "Parsed GET parameters:" << endl;
                        for (const auto& param : params) {
                            cout << "  " << param.first << " = " << param.second << endl;
                        }
                    }
                }
                
                // 如果是根路径,返回HTML
                if (path == "/" || path == "/index.html") {
                    // 读取HTML文件
                    ifstream in("index.html", ios::binary);
                    if (in.is_open()) {
                        in.seekg(0, ios::end);
                        int file_size = in.tellg();
                        in.seekg(0, ios::beg);
                        
                        char* file_content = new char[file_size + 1];
                        in.read(file_content, file_size);
                        file_content[file_size] = '\0';
                        in.close();
                        
                        // 构建HTTP响应
                        string response = "HTTP/1.1 200 OK\r\n";
                        response += "Content-Type: text/html; charset=UTF-8\r\n";
                        response += "Content-Length: " + to_string(file_size) + "\r\n";
                        response += "Connection: close\r\n";
                        response += "\r\n";
                        response += string(file_content, file_size);
                        
                        send(sock, response.c_str(), response.size(), 0);
                        delete[] file_content;
                    } else {
                        // 404 Not Found
                        string response = "HTTP/1.1 404 Not Found\r\n";
                        response += "Content-Type: text/html; charset=UTF-8\r\n";
                        response += "Content-Length: 48\r\n";
                        response += "\r\n";
                        response += "<html><body><h1>404 Not Found</h1></body></html>";
                        send(sock, response.c_str(), response.size(), 0);
                    }
                } else {
                    // 404 Not Found
                    string response = "HTTP/1.1 404 Not Found\r\n";
                    response += "Content-Type: text/html; charset=UTF-8\r\n";
                    response += "Content-Length: 48\r\n";
                    response += "\r\n";
                    response += "<html><body><h1>404 Not Found</h1></body></html>";
                    send(sock, response.c_str(), response.size(), 0);
                }
            }
            
            close(sock);
            exit(0);
        }
        
        close(sock);
        waitpid(-1, nullptr, WNOHANG); // 非阻塞等待子进程
    }
    
    close(listen_sock);
    return 0;
}

此时浏览器刚开始请求到服务器,如下:

可以看到,如果使用提交表单的方法为 POST 方法,填充完用户名和密码并点击提交按钮后,对应提交的参数不会在 URL 当中体现出来,而是会通过请求正文将这两个参数传递给服务器。服务器端需要通过读取请求正文来获取用户提交的数据。如下:

3、注意事项

数据敏感性

  • 当我们使用 GET 方法时,提交的参数会回显到 URL 当中,因此 GET 方法一般用于处理数据不敏感的情况。

  • 如果你要传递的数据比较私密(如密码、银行卡号等),一定要使用 POST 方法。

  • 不过,再次强调,POST 方法并非更安全,只是相对更私密,因为 GET 和 POST 方法传参时都是明文传送,要实现真正的安全传输,必须使用加密技术。

通过以上对 HTTP 方法的详细讲解以及 Postman 和 TCP 套接字的演示,相信你对 HTTP 方法,尤其是 GET 和 POST 方法有了更深入的理解。在实际开发中,应根据具体需求合理选择合适的 HTTP 方法,以确保数据传输的正确性和安全性。


五、HTTP常见方法

HTTP (Hypertext Transfer Protocol) 定义了多种请求方法,用于指示要对给定资源执行的操作。

1、GET 方法(重点)

用途:用于请求 URL 指定的资源,是最常用的 HTTP 方法之一。

示例

cpp 复制代码
GET /index.html HTTP/1.1
Host: www.example.com

特性

  • 请求指定的资源,服务器返回解析后的响应内容

  • 参数通常附加在 URL 后(如 ?key1=value1&key2=value2

  • 有长度限制(受 URL 最大长度限制)

  • 可被缓存、保留在历史记录中

  • 幂等的(多次相同请求应产生相同效果)

表单验证 :在 HTML 表单(HTML 表单 | 菜鸟教程)中,当 method="get" 时,表单数据会附加在 URL 上发送:

html 复制代码
<form action="/submit" method="get">
  <input type="text" name="username">
  <input type="submit" value="Submit">
</form>

服务器端处理示例(C++):

cpp 复制代码
std::string GetFileContentHelper(const std::string &path) {
    // 简单的二进制文件读取代码
    std::ifstream in(path, std::ios::binary);
    if (!in.is_open()) return "";
    
    in.seekg(0, in.end);
    int filesize = in.tellg();
    in.seekg(0, in.beg);
    
    std::string content;
    content.resize(filesize);
    in.read((char *)content.c_str(), filesize);
    in.close();
    return content;
}

2、POST 方法(重点)

用途:用于传输实体的主体,通常用于提交表单数据或上传文件。

示例

cpp 复制代码
POST /submit.cgi HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

username=john&age=30

特性

  • 数据包含在请求体中

  • 没有长度限制

  • 不会被缓存

  • 不会保留在历史记录中

  • 不幂等(多次提交可能产生副作用)

表单验证 :当 method="post" 时,表单数据在请求体中发送:

html 复制代码
<form action="/submit" method="post">
  <input type="text" name="username">
  <input type="submit" value="Submit">
</form>

3、PUT 方法(不常用)

用途:用于传输文件,将请求报文主体中的文件保存到请求 URL 指定的位置。

示例

cpp 复制代码
PUT /example.html HTTP/1.1
Host: www.example.com
Content-Type: text/html
Content-Length: 1256

<html>...</html>

特性

  • 用于创建或替换目标资源

  • 客户端需要指定资源的完整表示

  • 在 RESTful API 中常用于更新资源

  • 幂等的(多次相同请求效果相同)

4、HEAD 方法

用途:与 GET 方法类似,但不返回报文主体部分,仅返回响应头。

示例

cpp 复制代码
HEAD /index.html HTTP/1.1
Host: www.example.com

特性

  • 用于获取资源的元信息而不传输实际内容

  • 常用于:

    • 检查资源是否存在

    • 检查资源是否被修改(结合 Last-Modified 或 ETag)

    • 检查服务器性能

curl 示例

bash 复制代码
# 完整请求(显示响应头和体)
curl -i www.baidu.com
bash 复制代码
# 仅显示响应头
curl --head www.baidu.com

5、DELETE 方法(不常用)

用途:用于删除文件,是 PUT 的相反方法。

示例

cpp 复制代码
DELETE /example.html HTTP/1.1
Host: www.example.com

特性

  • 请求服务器删除指定的资源

  • 在 RESTful API 中用于删除资源

  • 幂等的(多次删除已不存在的资源不应报错)

6、OPTIONS 方法

用途:用于查询针对请求 URL 指定的资源支持的方法。

示例

cpp 复制代码
OPTIONS * HTTP/1.1
Host: www.example.com

特性

  • 返回服务器支持的 HTTP 方法

  • 常用于 CORS (跨域资源共享) 预检请求

  • 可用于检查服务器功能而不实际访问资源

服务器响应示例

cpp 复制代码
HTTP/1.1 200 OK
Allow: GET, HEAD, POST, OPTIONS
Content-Type: text/plain
Content-Length: 0

不支持 OPTIONS 的服务器响应

cpp 复制代码
HTTP/1.1 405 Not Allowed
Content-Type: text/html
Content-Length: 166

<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
</body>
</html>

7、其他 HTTP 方法

TRACE 方法

  • 用途:回显服务器收到的请求,主要用于诊断。

CONNECT 方法

  • 用途:用于代理服务器,建立隧道连接(如 HTTPS)。

PATCH 方法

  • 用途:用于对资源进行部分修改(RESTful API 中常用)。

8、方法特性总结

方法 幂等 安全 缓存 请求体 典型用途
GET 获取资源
HEAD 获取元信息
POST 提交数据
PUT 替换资源
DELETE 删除资源
OPTIONS 获取支持的方法
PATCH 部分更新资源

说明

  • 幂等:多次相同请求应产生相同效果

  • 安全:不会修改服务器资源状态

  • 缓存:响应是否可被缓存

9、实际应用建议

  • GET vs POST

    • 使用 GET 获取数据(参数在 URL 中可见)

    • 使用 POST 提交数据(参数在请求体中)

  • RESTful API 设计

    • GET /users - 获取用户列表

    • POST /users - 创建新用户

    • GET /users/1 - 获取特定用户

    • PUT /users/1 - 更新特定用户

    • DELETE /users/1 - 删除特定用户

  • 安全考虑

    • 不要使用 GET 传输敏感信息(参数可见于 URL 和历史记录)

    • 使用 HTTPS 保护所有方法的数据传输

  • 性能优化

    • 使用 HEAD 先检查资源是否存在再决定是否下载

    • 使用 OPTIONS 预先检查服务器支持的方法

理解这些 HTTP 方法及其特性对于开发健壮的 Web 应用程序和 API 至关重要。

相关推荐
小许学java1 小时前
网络编程套接字
java·网络·udp·socket·tcp·套接字
inquisiter1 小时前
cove-salus-tellus测试程序时序逻辑
linux·服务器·网络·riscv
代码不行的搬运工1 小时前
使用多代理间 AS 诊断系统检测和恢复前缀劫持(2010)
网络·bgp安全
怕什么真理无穷1 小时前
解析OSI 七层模型
网络
⁤⁢初遇1 小时前
Linux------线程概念与控制
linux·运维·服务器
Forest_HAHA2 小时前
<13>_Linux网络基础(下)
linux·服务器
斯普信专业组2 小时前
Calico网络架构与实现深度解析(上)
网络·架构
luoganttcc2 小时前
can 协议 600#09000000000000c0 分析
网络
痕忆丶2 小时前
本地搭建简易RTSP流媒体服务器
网络