Http协议介绍

 1.Http协议介绍

HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最广泛的应用层协议,用于在客户端(如浏览器)和服务器之间传输超文本(如网页)数据。它是万维网(WWW)数据通信的基础,设计简单灵活,支持多种数据格式的传输。


1.HTTP 核心特点

  1. 无状态协议
    默认不记录之前的请求或会话信息(后续可通过CookieSession等技术实现状态管理)。

  2. 基于请求-响应模型
    客户端发送请求(Request),服务器返回响应(Response)。

  3. 支持多种方法
    如 GET(获取资源)、POST(提交数据)、PUT(更新资源)、DELETE(删除资源)等。

  4. 可扩展性强
    通过请求头/响应头(Headers)传递额外信息,支持缓存、压缩、身份验证等功能。


2.HTTP 工作原理

  1. 建立连接
    客户端通过TCP/IP(默认端口80)与服务器连接(HTTP/1.1默认持久连接,HTTP/2支持多路复用)。

  2. 发送请求
    请求报文包括:

    • 请求行:方法(如GET)、URL(如/index.html)、协议版本(如HTTP/1.1)。

    • 请求头HostUser-AgentAccept等元信息。

    • 请求体(可选):如POST提交的表单数据。

    GET /index.html HTTP/1.1
    Host: www.example.com
    User-Agent: Mozilla/5.0
  3. 服务器处理并返回响应
    响应报文包括:

    • 状态行:状态码(如200 OK)、协议版本。

    • 响应头Content-TypeContent-Length等。

    • 响应体:实际数据(如HTML、JSON)。

      HTTP/1.1 200 OK
      Content-Type: text/html
      Content-Length: 1234
      
      <html>...</html>
  4. 关闭连接
    (非持久连接时断开TCP连接)。


3.HTTP 版本演进

版本特性
HTTP/1.0每次请求需重新建立连接,效率低。
HTTP/1.1默认持久连接、管道化请求、支持分块传输(Transfer-Encoding: chunked)。
HTTP/2二进制分帧、多路复用、头部压缩、服务器推送,大幅提升性能。
HTTP/3基于QUIC协议(UDP),解决队头阻塞,提升弱网环境下的传输效率。

4.常见状态码

  • 200 OK:请求成功。

  • 301 Moved Permanently:永久重定向。

  • 400 Bad Request

  • 404 Not Found:资源不存在。

  • 500 Internal Server Error:服务器内部错误。


HTTP 与 HTTPS 的区别

  • HTTPS = HTTP + SSL/TLS加密,通过端口443传输,保证数据安全性(防窃听、篡改)。

  • HTTPS需配置数字证书(如Let's Encrypt签发)。

2. curl使用

curl 是一个非常强大的命令行工具,用于在不同类型的服务器之间传输数据,支持多种协议(如 HTTP、HTTPS、FTP 等)。以下是一些常见的 curl 使用方法:

1.基本用法

  • 发送 GET 请求

    curl http://example.com

    这是最基本的用法,用于从指定的 URL 获取数据。

  • 发送 POST 请求

    curl -X POST http://example.com -d "param1=value1&param2=value2"

    -X POST 指定请求方法为 POST,-d 用于指定要发送的数据。

  • 发送 PUT 请求

    curl -X PUT http://example.com -d "param1=value1&param2=value2"

    -X PUT 指定请求方法为 PUT,同样使用 -d 发送数据。

  • 发送 DELETE 请

    curl -X DELETE http://example.com

    -X DELETE 指定请求方法为 DELETE。

2.高级用法

  • 设置请求

    curl -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" http://example.com

    -H 参数用于添加自定义的 HTTP 请求头。

  • 上传文件

    bash
    curl -X POST -F "file=@/path/to/file" http://example.com/upload

    -F 参数用于上传文件,@ 后面跟文件路径。

  • 下载文件

    curl -O http://example.com/file.zip

    -O 参数会将文件保存为原文件名。

    curl -o custom_filename.zip http://example.com/file.zip

    -o 参数可以指定保存的文件名。

  • 查看响应头

    curl -I http://example.com

    -I 参数只获取 HTTP 响应头。

3.具体使用

curl -X POST -H "Filename: example.txt" --data-binary "@/home/book/Desktop/chat/data/local/example.txt" http://localhost:8080/uploadtp://localhost:8080/upload
  1. -X POST
    指定 HTTP 请求方法为 POST(通常用于上传操作)。

  2. -H "Filename: example.txt"
    添加一个自定义请求头,键为 Filename,值为 example.txt
    作用:服务器可能通过此头部获取客户端指定的文件名,而非从文件数据中解析。

  3. --data-binary @/path/to/file
    --data-binary 表示发送原始二进制数据(不会进行编码/转义)。
    @ 符号告诉 curl 从指定路径读取文件内容(这里是 /home/book/Desktop/chat/data/local/example.txt)。

  4. http://localhost:8080/upload

 curl -o /home/book/Desktop/chat/data/download/example.txt http://localhost:8081/download/example.txt
curl -o /home/book/Desktop/chat/data/download/example.txt http://localhost:8081/download/6ab618eb-cee1-4809-bd42-22c4d21ca535
  1. -o /path/to/save/file

    • 将服务器返回的数据保存到指定路径(而不是输出到终端)。

  2. http://localhost:8081/download/example.txt

    • 请求的URL,假设服务端在 8081 端口提供了文件下载接口。

    • 路径 /download/example.txt 需与服务端路由匹配。

4.libcurl 

sudo apt update
sudo apt install libcurl4-openssl-dev
1. 初始化和清理

在使用 libcurl 之前,需要初始化一个 CURL 对象,并在使用完成后进行清理。

#include <stdio.h>
#include <curl/curl.h>

int main() {
    CURL *curl;
    CURLcode res;

    // 初始化CURL对象
    curl = curl_easy_init();
    if(curl) {
        // 设置选项和执行请求
        // ...

        // 清理CURL对象
        curl_easy_cleanup(curl);
    }

    return 0;
}
2. 设置选项

libcurl 提供了大量的选项,用于配置请求的各种参数。这些选项通过 curl_easy_setopt 函数设置。

  • 设置 URLCURLOPT_URL,指定请求的 URL。

    curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
  • 设置超时时间CURLOPT_TIMEOUT,单位为秒

    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); // 设置超时时间为10秒
  • 启用 SSL 验证CURLOPT_SSL_VERIFYPEERCURLOPT_SSL_VERIFYHOST

    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 禁用SSL证书验证
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // 禁用主机名验证
  • 设置 HTTP 请求头CURLOPT_HTTPHEADER

    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Accept: application/json");
    headers = curl_slist_append(headers, "Authorization: Bearer YOUR_TOKEN");
    
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    
    curl_slist_free_all(header);
3. 获取响应信息

可以通过设置选项来获取响应信息,例如响应头和响应体。

size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) {
    printf("Header: %s", buffer);
    return size * nitems;
}

curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, NULL);

获取响应体

size_t write_callback(char *buffer, size_t size, size_t nitems, void *userdata) {
    printf("Body: %s", buffer);
    return size * nitems;
}

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);

 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);

这行代码设置了自定义的回调函数,用于处理响应体数据。

  • CURLOPT_WRITEFUNCTION:这是libcurl的一个选项,用于指定一个回调函数,当接收到响应体数据时,libcurl会调用这个函数。

  • write_callback:这是一个用户定义的函数,libcurl会在接收到响应体数据时调用它。这个函数的原型通常如下:

size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp);
  • contents:指向接收到的数据的指针。

  • size:每个数据块的大小。

  • nmemb:数据块的数量。

  • userp:用户提供的数据指针,通过CURLOPT_WRITEDATA设置。

curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

这行代码设置了传递给回调函数的用户数据。

  • CURLOPT_WRITEDATA:这是libcurl的一个选项,用于指定一个用户数据指针,这个指针将被传递给CURLOPT_WRITEFUNCTION指定的回调函数。

  • &response:这是用户提供的数据的地址。在这个例子中,response可能是一个变量,用于存储响应体数据。

这行代码的作用是将response的地址传递给write_callback函数,这样write_callback函数就可以将接收到的数据存储到response中。

 4. 执行请求

使用 curl_easy_perform 函数执行请求。该函数会阻塞,直到请求完成。

res = curl_easy_perform(curl);

if(res != CURLE_OK) {
    fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}

5. 示例代码
#include <stdio.h>
#include <curl/curl.h>

size_t write_callback(char *buffer, size_t size, size_t nitems, void *userdata) {
    printf("Body: %s", buffer);
    return size * nitems;
}

int main() {
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);

        res = curl_easy_perform(curl);

        if(res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }

        curl_easy_cleanup(curl);
    }

    return 0;
}
6.编译和运行
gcc -o example example.c -lcurl

在C++中使用libcurl的基本思路与C语言类似,但可以通过C++的特性(如智能指针、类封装等)来提高代码的可读性和安全性。以下是一个C++版本的示例,展示如何使用libcurl进行HTTP请求。

1. 包含头文件

在C++中,libcurl的头文件和C语言中一样,可以直接包含<curl/curl.h>

2. 初始化和清理

使用libcurl时,仍然需要初始化CURL对象,并在使用完成后进行清理。在C++中,可以通过RAII(Resource Acquisition Is Initialization)机制来管理资源,例如使用智能指针。

3. 设置选项和执行请求

设置选项和执行请求的逻辑与C语言相同,但可以利用C++的特性来简化代码。

4. 示例代码

以下是一个完整的C++示例,展示如何使用libcurl发起一个HTTP GET请求并打印响应体。

#include <iostream>
#include <curl/curl.h>

// 回调函数,用于处理响应体
size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
    size_t totalSize = size * nmemb;
    std::string response(static_cast<char*>(contents), totalSize);
    std::cout << "Response Body: " << response << std::endl;
    return totalSize;
}

int main() {
    CURL* curl;
    CURLcode res;

    // 初始化CURL对象
    curl = curl_easy_init();
    if (curl) {
        // 设置URL
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");

        // 设置回调函数,用于处理响应体
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);

        // 执行请求
        res = curl_easy_perform(curl);

        // 检查错误
        if (res != CURLE_OK) {
            std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
        }

        // 清理CURL对象
        curl_easy_cleanup(curl);
    }

    return 0;
}

g++ -o example example.cpp -lcurl

3. HTTP 请求

你的问题涉及到 HTTP 请求的两种常见方式:路径参数(Path Parameters)和查询参数(Query Parameters)。这两种方式都可以用来传递数据,但它们在语义和用途上有所不同。

1. 查询参数(Query Parameters)

查询参数是附加在 URL 路径后面的键值对,通常用于传递额外的信息。它们以 ? 开始,多个参数用 & 分隔。查询参数的主要用途包括:

  • 过滤和排序:在 API 请求中,查询参数常用于指定过滤条件或排序方式。

  • 分页:指定页码和每页显示的条数。

  • 搜索:传递搜索关键词。

  • 其他动态数据:传递动态生成的数据,如时间戳、随机值等。

示例

假设你有一个 API,用于获取用户列表,并支持分页和排序:

GET /users?page=1&limit=10&sort=asc

这里:

  • page=1 表示请求第一页。

  • limit=10 表示每页显示 10 条记录。

  • sort=asc 表示按升序排序。

2. 路径参数(Path Parameters)

路径参数是嵌入在 URL 路径中的变量部分,通常用于指定资源的唯一标识符。路径参数的主要用途包括:

  • 资源标识:指定要操作的具体资源。

  • 层次结构:表示资源的层次结构。

示例

假设你有一个 API,用于获取特定用户的详细信息:

GET /users/12345

这里:

  • 12345 是用户的唯一标识符。

3. 你的场景

在你的场景中,你有一个下载接口,客户端需要指定要下载的文件块的 chunk_id。你可以选择使用查询参数或路径参数来传递 chunk_id

使用查询参数
std::string url = "/internal_download?chunk_id=" + chunk.chunk_id;
auto res = client.Get(url.c_str());

服务器端:

CROW_ROUTE(app, "/internal_download")
    .methods("GET"_method)([](const crow::request &req) {
        std::string chunk_id = req.url_params.get("chunk_id");
        return dfs::DownloadManager::downloadById(chunk_id);
    });
使用路径参数
std::string url = "/internal_download/" + chunk.chunk_id;
auto res = client.Get(url.c_str());

服务器端:

CROW_ROUTE(app, "/internal_download/<string>")
    .methods("GET"_method)([](const crow::request &req, std::string chunk_id) {
        return dfs::DownloadManager::downloadById(chunk_id);
    });

4. 选择哪种方式更好?

使用查询参数的优点
  • 灵活性:查询参数可以传递多个参数,适合复杂的请求。

  • 语义清晰:对于动态数据(如分页、排序、搜索等),查询参数更符合语义。

使用路径参数的优点
  • 简洁性:路径参数使 URL 更简洁,适合传递资源的唯一标识符。

  • RESTful:路径参数更符合 RESTful API 的设计原则,使 URL 更具可读性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值