解锁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 至关重要。

相关推荐
网安情报局4 小时前
除了 CDN,DDoS 攻击还有哪些更有效的防护方式?
网络
代码AI弗森4 小时前
一文理清楚“算力申请 / 成本测算 / 并发评估”
java·服务器·数据库
Promise微笑5 小时前
2026年国产替代油介损测试仪:油介损全场景解决方案与技术演进
大数据·网络·人工智能
^—app5668665 小时前
游戏运存小启动不起来临时解决方法
运维·服务器
志栋智能6 小时前
超自动化安全:构建智能安全运营的核心引擎
大数据·运维·服务器·数据库·安全·自动化·产品运营
AnalogElectronic7 小时前
linux 测试网络和端口是否连通的命令详解
linux·网络·php
Edward111111118 小时前
4月28日防火墙问题
linux·运维·服务器
想学后端的前端工程师8 小时前
【补充内外网突然不通的情况】
运维·服务器
Rust研习社8 小时前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
灰子学技术8 小时前
Envoy HTTP 流量层面的 Metric 指标分析
网络·网络协议·http