我是靠谱客的博主 安详音响,最近开发中收集的这篇文章主要介绍HTTP协议及相关编程开发(C/C++),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

01 特点

1.1 http的特点

基于tcp/ip、一种网络应用层协议、超文本传输协议HyperText Transfer Protocol
工作方式:客户端请求服务端应答的模式
快速:无状态连接
灵活:可以传输任意对象,对象类型由Content-Type标记
客户端请求request消息包括以下格式:请求行(request line)、请求头部(header)、空行、请求数据
在这里插入图片描述
服务端响应response也由四个部分组成,分别是:状态行、消息报头、空行、响应正文
在这里插入图片描述

1.2 请求方法

http请求可以使用多种请求方法。
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。

HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

HTTP2.0 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

参考链接:https://baike.baidu.com/item/HTTP%202.0/12520156?fr=aladdin

1 GET 请求指定的页面信息,并返回实体主体。
2 HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。
5 DELETE 请求服务器删除指定的页面。
6 CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
7 OPTIONS 允许客户端查看服务器的性能。
8 TRACE 回显服务器收到的请求,主要用于测试或诊断。

1.3 区别

http协议最常见的两种方法GET和POST,这几点答案其实有几点并不准确

请求缓存:GET 会被缓存,而post不会

收藏书签:GET可以,而POST不能

保留浏览器历史记录:GET可以,而POST不能

用处:get常用于取回数据,post用于提交数据

安全性:post比get安全

请求参数:querystring 是url的一部分get、post都可以带上。 get的querystring(仅支持urlencode编码),post的参数是放在body(支持多种编码)

请求参数长度限制:get请求长度最多1024kb,post对请求数据没有限制

02 常见的误区

get和post误区

2.1 误区一

“用处:get常用于取回数据,post用于提交数据”

请求参数
get是querystring(仅支持urlencode编码),post是放在body(支持多种编码)
query参数是URL的一部分,而GET、POST等是请求方法的一种,不管是哪种请求方法,都必须有URL,而URL的query是可选的,可有可无。

2.2 误区二

“请求参数长度限制:get请求长度最多1024kb,post对请求数据没有限制”

我想说的是GET方法提交的url参数数据大小没有限制,在http协议中没有对url长度进行限制(不仅仅是querystring的长度),这个限制是特定的浏览器及服务器对它的限制

2.3 误区三

“post比get安全性要高”

这里的安全是相对性,并不是真正意义上的安全,通过get提交的数据都将显示到url上,页面会被浏览器缓存,其他人查看历史记录会看到提交的数据,而post不会。另外get提交数据还可能会造成CSRF攻击。

3 http状态码附录

3.1 状态码1xx

100 Continue:
服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求。
101 Switching Protocols:
服务器转换协议:服务器将遵从客户的请求转换到另外一种协议。
102: 由WebDAV(RFC 2518):
扩展的状态码,代表处理将被继续执行
3.2 状态码2xx:成功
200 OK:
请求成功(其后是对GET和POST请求的应答文档。)
201 Created:
请求被创建完成,同时新的资源被创建。
202 Accepted:
供处理的请求已被接受,但是处理未完成。
203 Non-authoritative Information:
文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝。
204 No Content:
没有新文档。浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的。
205 Reset Content:
没有新文档。但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容。
206 Partial Content:
客户发送了一个带有Range头的GET请求,服务器完成了它。
3.3 状态码3xx:重定向
300 Multiple Choices:
多重选择。链接列表。用户可以选择某链接到达目的地。最多允许五个地址。
301 Moved Permanently:
所请求的页面已经转移至新的url
302 Found:
所请求的页面已经临时转移至新的url。
303 See Other:
所请求的页面可在别的url下被找到。
304 Not Modified:
未按预期修改文档。客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
305 Use Proxy:
客户请求的文档应该通过Location头所指明的代理服务器提取。
306 Unused:
此代码被用于前一版本。目前已不再使用,但是代码依然被保留。
307 Temporary Redirect:
被请求的页面已经临时移至新的url。
3.4 状态码4xx:客户端错误
400 Bad Request:
服务器未能理解请求。
401 Unauthorized:
被请求的页面需要用户名和密码。
401.1:
登录失败。
401.2:
服务器配置导致登录失败。
401.3:
由于 ACL 对资源的限制而未获得授权。
401.4:
筛选器授权失败。
401.5:
ISAPI/CGI 应用程序授权失败。
401.7:
访问被 Web 服务器上的 URL 授权策略拒绝。这个错误代码为 IIS 6.0 所专用。
402 Payment Required:
此代码尚无法使用。
403 Forbidden:
对被请求页面的访问被禁止。
404 Not Found:
服务器无法找到被请求的页面。
405 Method Not Allowed:
请求中指定的方法不被允许。
406 Not Acceptable:
服务器生成的响应无法被客户端所接受。
407 Proxy Authentication Required:
用户必须首先使用代理服务器进行验证,这样请求才会被处理。
408 Request Timeout:
请求超出了服务器的等待时间。
409 Conflict:
由于冲突,请求无法被完成。
410 Gone:
被请求的页面不可用。
411 Length Required:
“Content-Length” 未被定义。如果无此内容,服务器不会接受请求。
412 Precondition Failed:
请求中的前提条件被服务器评估为失败。
413 Request Entity Too Large:
由于所请求的实体的太大,服务器不会接受请求。
414 Request-url Too Long:
由于url太长,服务器不会接受请求。当post请求被转换为带有很长的查询信息的get请求时,就会发生这种情况。
415 Unsupported Media Type:
由于媒介类型不被支持,服务器不会接受请求。
416 Requested Range Not Satisfiable:
服务器不能满足客户在请求中指定的Range头。
417 Expectation Failed:
执行失败。
423:
锁定的错误。
3.5 状态码5** 服务端错误
500 Internal Server Error:
请求未完成。服务器遇到不可预知的情况。
501 Not Implemented:
请求未完成。服务器不支持所请求的功能。
502 Bad Gateway:
请求未完成。服务器从上游服务器收到一个无效的响应。
503 Service Unavailable:
请求未完成。服务器临时过载或宕机。
504 Gateway Timeout:
网关超时。
505 HTTP Version Not Supported:
服务器不支持请求中指明的HTTP协议版本。

HTTP请求头之User-Agent

那么User-Agent到底是什么呢?
User-Agent会告诉网站服务器,访问者是通过什么工具来请求的,如果是爬虫请求,一般会拒绝,如果是用户浏览器,就会应答。

User-Agent字段解释
简要版解释:

我用的Chrome浏览器,查看User-Agent的结果:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36

User-Agent通常格式:

Mozilla/5.0 (平台) 引擎版本 浏览器版本号

第一部分:Mozilla/5.0
由于历史上的浏览器大战,当时想获得图文并茂的网页,就必须宣称自己是 Mozilla 浏览器。此事导致如今User-Agent里通常都带有Mozilla字样,出于对历史的尊重,大家都会默认填写该部分。

第二部分:平台这部分可由多个字符串组成,用英文半角分号分开
Windows NT 10.0是指我使用的操作系统的版本,比如我使用的win10对应的就是Windows NT 10.0,如果我使用win7对应的就是Windows NT 6.1。
Win64; x64是指我的操作系统是64位的

Windows系统下

Windows NT 5.0 // 如 Windows 2000 
Windows NT 5.1 // 如 Windows XP
Windows NT 6.0 // 如 Windows Vista 
Windows NT 6.1 // 如 Windows 7
Windows NT 6.2 // 如 Windows 8
Windows NT 6.3 // 如 Windows 8.1
Windows NT 10.0 // 如 Windows 10
Win64; x64 // Win64 on x64
WOW64 // Win32 on x64

Linux系统下:

X11; Linux i686; // Linux 桌面,i686 版本
X11; Linux x86_64; // Linux 桌面,x86_64 版本
X11; Linux i686 on x86_64 // Linux 桌面,运行在 x86_64 的 i686 版本

第三部分:引擎版本
AppleWebKit/537.36 (KHTML, like Gecko)…Safari/537.36,历史上,苹果依靠了WebKit内核开发出Safari浏览器,WebKit包含了WebCore引擎,而WebCore又从KHTML衍生而来。由于历史原因,KHTML引擎需要声明自己是“类似Gecko”的,因此引擎部分这么写。再后来,Google开发Chrome也是用了WebKit内核,于是也跟着这么写。
借用Littern的一句话:“Chrome 希望能得到为Safari编写的网页,于是决定装成Safari,Safari使用了WebKit渲染引擎,而WebKit呢又伪装自己是KHTML,KHTML呢又是伪装成Gecko的。同时所有的浏览器又都宣称自己是Mozilla。”。
不过,后来Chrome 28某个版本改用了blink内核,但还是保留了这些字符串。而且,最近的几十个版本中,这部分已经固定,没再变过

第四部分:浏览器版本
本人用的是Chrome浏览器,其中60.0 是大版本,3100是持续增大的一个数字,而0则是修补漏洞的小版本。

HTTP开发

1. winhttp

以下是POST的代码,GET的代码也是大同小异,只是https头部信息有所不用

#include "stdafx.h"
#include "windows.h"
#include "winhttp.h"
#include "wchar.h"
#include "wincrypt.h"
#include <comdef.h>
 
#pragma comment(lib, "Winhttp.lib")
#pragma comment(lib, "Crypt32.lib")
 
wstring string2wstring(const string &str)
{
    _bstr_t tmp = str.c_str();
    wchar_t* pwchar  = (wchar_t*)tmp;
    wstring ret = pwchar;
    return ret;
}
 
void winhttp_client_post(){
 
LPSTR pszData = "WinHttpWriteData Example";
DWORD dwBytesWritten = 0;
BOOL  bResults = FALSE;
HINTERNET hSession = NULL,
          hConnect = NULL,
          hRequest = NULL;
 
			
 
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(  L"A WinHTTP Example Program/1.0", 
                         WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                         WINHTTP_NO_PROXY_NAME, 
                         WINHTTP_NO_PROXY_BYPASS, 0);
 
// Specify an HTTP server.
if (hSession)
    hConnect = WinHttpConnect( hSession, L"www.wingtiptoys.com",
                               INTERNET_DEFAULT_HTTPS_PORT, 0);
 
// Create an HTTP Request handle.
if (hConnect)
    hRequest = WinHttpOpenRequest( hConnect, L"POST", 
                                   L"/token", 
                                   NULL, WINHTTP_NO_REFERER, 
                                   WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                   0);
 
// Set HTTP Options
DWORD dwTimeOut = 3000;
DWORD dwFlags =SECURITY_FLAG_IGNORE_UNKNOWN_CA |
                SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |
                SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
                SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
 
BOOL bRet = WinHttpSetOption(hRequest, WINHTTP_OPTION_CONNECT_TIMEOUT, &dwTimeOut, sizeof(DWORD));
bRet = WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));
bRet = WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0);
 
//加上OAuth认证需要的header信息:
std::string client_id = "test client id";
std::string client_secure = "test client security";
// client id and secure need base64 encode
std::wstring strHeader = L"Content-type:application/x-www-form-urlencodedrn";
strHeader += L"Authorization: Basic ";
//strHeader += string2wstring(tmsstring) +L"rn"; //tmsstring is client and secure after base64 encoding
 
bRet = WinHttpAddRequestHeader(hRequest, strHeader.c_str(), strHeader.length(), WINHTTP_ADDREQ_FLAG_ADD|WINHTTP_ADDREQ_FLAG_REPLACE);
// Send a Request.
 
std::string strTmp = "grant_type=client_credentials"; //OAuth认证模式是客户端模式
if (hRequest) 
    bResults = WinHttpSendRequest( hRequest, 
                                   WINHTTP_NO_ADDITIONAL_HEADERS,
                                   0, (LPVOID)strTmp.c_str(), strTmp.length(), 
                                   strTmp.length(), 0);
 
// Write data to the server. don't need this step
/*if (bResults)
    bResults = WinHttpWriteData( hRequest, pszData, 
                                 (DWORD)strlen(pszData), 
                                 &amp;dwBytesWritten);
*/
// End the request.
if (bResults)
    bResults = WinHttpReceiveResponse( hRequest, NULL);
 
// Report any errors.
if (!bResults)
    printf("Error %d has occurred.n",GetLastError());
 
//接收服务器返回数据
if(bRet)
{
    char *pszOutBuf;
    DWORD dwSize = 0;
    DWORD dwDownLoaded = 0;
    std::string strJson; //返回的是Json格式
    
    do
     {
        if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
            {
                //error log
            }
        pszOutBuf = new char[dwSize+1];
        ZeroMemory(pszOutBuf, dwSize+1);
 
        if  (!WinHttpReadData( hRequest, (LPVOID)pszOutBuf, dwSize, &dwDownLoaded) )
            {
                //error log
            }
 
        strJson += pszOutBuf;
     }while(dwSize > 0);
}
 
 
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
 
}

参考链接:
https://cloud.tencent.com/developer/article/1383626

2. socket

方式1
一、如何建立与服务器之间的连接

HTTP基本TCP,所以我们需要与服务器建立连接,然后才能发送数据。
建立连接参考如下函数socket_open:

/*
*打开Socket,返回socketId,-1表示失败
*/
int socket_open(int IP,int Port,int type){
SOCKET socketId;
 struct sockaddr_in serv_addr;
  int status;
 
 socketId=socket(AF_INET,SOCK_STREAM,0);
 
 if((int)socketId<0)
 {
       printf("[ERROR]Create a socket failed!n");
       return -1;
 }
 
 memset(&serv_addr,0,sizeof(serv_addr));
 serv_addr.sin_family=AF_INET;
 serv_addr.sin_addr.s_addr = ntohl(IP);

   serv_addr.sin_port = htons((USHORT)Port);

   status=connect(socketId,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
    if(status!=0)
 {
    printf("[ERROR]Connecting failed!n"); 
    closesocket(socketId);
    return -1;
 }
 return socketId;
}
 调用方式如下:

int socketId=socket_open(0xC0A80001,808,0); //0xC0A80001是192.168.0.1的十六进制写法。

二、如何发送请求

发送数据要根据HTTP协议的要求附加协议头:

static const char* protocolHead="GET http://www.xxx.com/index.html HTTP/1.1n"
     "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*n"
     "Accept-Language: zh-cnn"
     "User-Agent:iPanelBrowser/2.0n"
     "Host: www.xxx.com:80n"
     "Connection: closenn"
     这里使用GET来获取指定URL的指定文档。
     建立连接后使用send将这些数据发送出去:
     send(socketId, protocolHead,strlen(protocolHead),0);
     发送完成HTTP请求后就等待接收数据。
三、如何接收数据

这里采用select循环查询的方式来判断有无数据到来:

struct timeval tm = {0,7};
     fd_set fds_r;
     int status;
     char recvBuf[4096]={0};
     FD_ZERO(&fds_r);
     FD_SET(socketId,&amp;fds_r);
     
status=select(socketId+ 1, &fds_r, 0, 0, &tm); //socketId在这里是最大的fd
     
     if(status > 0 && FD_ISSET(socketId, &fds_r))
{
         printf("Socket is readable...fd=[%d]n",socketId);
          recv(socketId,recvBuf,4096,0);
}

这样数据包就保存到缓冲区中了。

四、如何判断数据接收完成

首先对返回数据的状态进行判断,仅当状态为“ HTTP 200 OK ”时才表明正确返回,这时才对数据进行解析并保存,如果状态为HTTP 404 NOT FOUND或者其它状态则表明没有找到资源或者出现其它问题,可参考HTTP 1.1状态代码及其含义。
当数据正确返回时,为了将实际数据从协议中分离出来进行保存,需要对HTTP数据包进行解析得到Content-Length,然后在包含Content-Length的当前数据包或者随后的数据包中查找第一个空行,这就是内容(Content)的开始位置,再配合前面解析得到的Content-Length,就能够知道什么时候数据接收完成了。换行符为“rn”,也兼容“n”或者“r”,设换行符为^P ,则空行位于内容中间和结尾则"^p^p",开头则 ^p

基本就是上面这些,这四个问题解决了,那么整个问题也就解决了!
文章出处(http://www.diybl.com/course/3_program/c++/cppsl/2008227/101925.html)

c socket 发送http请求
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(){
int sockfd;
int len;
struct sockaddr_in address;
int result;
char *strings="GET /svnup/rewrite.php HTTP/1.1rnHost: 192.168.1.12rnConnection: Closernrn";
char ch;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.1.12");
address.sin_port = htons(80);
len = sizeof(address);
result = connect(sockfd,  (struct sockaddr *)&address, len);
if(result == -1){
    perror("oops: client1");
    return 1;
}
write(sockfd,strings,strlen(strings));
while(read(sockfd,&ch,1))
    printf("%c", ch);
close(sockfd);
return 1;
}
纯C++实现的HTTP请求(POST/GET),支持windows和linux,

进行简单的封装, 方便调用。实现如下:

#include "HttpConnect.h"
 
#ifdef WIN32
#pragma comment(lib,"ws2_32.lib")
#endif
 
HttpConnect::HttpConnect()
{
#ifdef WIN32
    //此处一定要初始化一下,否则gethostbyname返回一直为空
    WSADATA wsa = { 0 };
    WSAStartup(MAKEWORD(2, 2), &wsa);
#endif
}
 
HttpConnect::~HttpConnect()
{
 
}
void HttpConnect::socketHttp(std::string host, std::string request)
{
    int sockfd;
    struct sockaddr_in address;
    struct hostent *server;
 
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    address.sin_family = AF_INET;
    address.sin_port = htons(80);
    server = gethostbyname(host.c_str());
    memcpy((char *)&address.sin_addr.s_addr,(char*)server->h_addr, server->h_length);
 
    if(-1 == connect(sockfd,(struct sockaddr *)&address,sizeof(address))){
        DBG <<"connection error!"<<std::endl;
        return;
    }
 
    DBG << request << std::endl;
#ifdef WIN32
    send(sockfd, request.c_str(),request.size(),0);
#else
    write(sockfd,request.c_str(),request.size());
#endif
    char buf[1024]={0};
 
 
    int offset = 0;
    int rc;
 
#ifdef WIN32
    while(rc = recv(sockfd, buf+offset, 1024,0))
#else
    while(rc = read(sockfd, buf+offset, 1024))
#endif
    {
        offset += rc;
    }
 
#ifdef WIN32
    closesocket(sockfd);
#else
    close(sockfd);
#endif
    buf[offset] = 0;
    DBG << buf << std::endl;
 
}
 
void HttpConnect::postData(std::string host, std::string path, std::string post_content)
{
    //POST请求方式
    std::stringstream stream;
    stream << "POST " << path;
    stream << " HTTP/1.0rn";
    stream << "Host: "<< host << "rn";
    stream << "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3rn";
    stream << "Content-Type:application/x-www-form-urlencodedrn";
    stream << "Content-Length:" << post_content.length()<<"rn";
    stream << "Connection:closernrn";
    stream << post_content.c_str();
 
    socketHttp(host, stream.str());
}
 
void HttpConnect::getData(std::string host, std::string path, std::string get_content)
{
    //GET请求方式
    std::stringstream stream;
    stream << "GET " << path << "?" << get_content;
    stream << " HTTP/1.0rn";
    stream << "Host: " << host << "rn";
    stream <<"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3rn";
    stream <<"Connection:closernrn";
 
    socketHttp(host, stream.str());
}

调用方法:

    HttpConnect *http = new HttpConnect();
    http->getData("127.0.0.1", "/login", "id=liukang&pw=123");
    http->postData("127.0.0.1", "/login","id=liukang&pw=123");

3. curl

1.准备工作
  curl库和json库打导入,添加附加包含目录是include目录,添加预处理定义,添加外部依赖项

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.代码实现
// resful.cpp : 定义控制台应用程序的入口点。
//
 
#include "stdafx.h"
 
#include <stdio.h>
#include <iostream>
#include <Windows.h>
#include <stdlib.h>
#include <sys/types.h>
#include <http.h>
#include "stdafx.h"
#include <iostream>
#include <sstream>
#include "jsonjson.h"
#include "curlcurl.h"
using namespace std;
//#pragma comment(lib, "libcurl.lib")
wstring AsciiToUnicode(const string& str) 
{
    // 预算-缓冲区中宽字节的长度  
    int unicodeLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
    // 给指向缓冲区的指针变量分配内存  
    wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);
    // 开始向缓冲区转换字节  
    MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, pUnicode, unicodeLen);
    wstring ret_str = pUnicode;
    free(pUnicode);
    return ret_str;
}
 
string UnicodeToUtf8(const wstring& wstr) 
{
    // 预算-缓冲区中多字节的长度  
    int ansiiLen = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
    // 给指向缓冲区的指针变量分配内存  
    char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);
    // 开始向缓冲区转换字节  
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
    string ret_str = pAssii;
    free(pAssii);
    return ret_str;
}
 
 
string AsciiToUtf8(const string& str) 
{
    return UnicodeToUtf8(AsciiToUnicode(str));
}
 
//回调函数
size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) 
{
    string data((const char*) ptr, (size_t) size * nmemb);
 
    *((std::stringstream*) stream) << data << endl;
 
    return size * nmemb;
}
int _tmain(int argc, _TCHAR* argv[])
{
	CURL* curl = NULL;
	CURLcode res = CURLE_OK;
	//HTTP报文头
	struct curl_slist* headers = NULL;
	
 
	Json::Value value;
    value["dst_uid"]=Json::Value("wZdxqE9zZUlSrB");
	value["item_uid"]=Json::Value("AqRxqE9zZUlSrB");
	value["txt_lines"]=Json::Value("YWJjZGVmPXNzcyZhYmNkZWbI1cbaPTIwMTktMDQtMTM=");
    Json::Reader reader;
		
    std::string strResult = value.toStyledString();
	strResult = AsciiToUtf8(strResult);
    Json::Value result;
    //测试构造字符串内容
    /*if (reader.parse(strResult,result))
    {
            if(!result["dst_uid"].isNull())
            {
                    cout<<result["id"].asInt()<<std::endl;
            }
    }*/
    std::cout<<value.toStyledString().c_str()<<std::endl;
  /*这个函数只能用一次,如果这个函数在curl_easy_init函数调用时还没调用,
  它讲由libcurl库自动调用,所以多线程下最好在主线程中调用一次该函数以防止在线程
  中curl_easy_init时多次调用*/
  curl_global_init(CURL_GLOBAL_ALL);
  //初始化easy handler句柄
  curl = curl_easy_init();
  if (curl) {
    //构建HTTP报文头
    curl_slist *http_headers = NULL;
    http_headers = curl_slist_append(http_headers, "Accept: application/json");
    http_headers = curl_slist_append(http_headers, "Content-Type: application/json");//text/html
    http_headers = curl_slist_append(http_headers, "charsets: utf-8");
	//设置method为post
	//curl_easy_setopt(m_pCurlHandlder, CURLOPT_POST, 1);
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
	//设置post请求的url地址
    curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:8080/Pub_Service/signer/do");
	//设置HTTP头
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_headers);
	//设置发送超时时间
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
 
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
	//执行单条请求
	curl_easy_setopt(curl,CURLOPT_POSTFIELDS,strResult.c_str());
	//curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, value.toStyledString().size());
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);//设置回调函数
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
	  //curl_easy_strerror进行出错打印
      cout << "curl_easy_perform() failed:" << curl_easy_strerror(res);
    }
    curl_slist_free_all(headers);
	//这个调用用来结束一个会话.与curl_easy_init配合着用
    curl_easy_cleanup(curl);
	//在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数
	curl_global_cleanup();
	return 0;
	}
3.curl获取状态码

命令行种用curl 获取HTTP返回的状态码

curl -I  -m  10  -o  /dev/null  -s  -w  %{http_code}   https://www.baidu.com
 curl -sL  -w   "http_code:%{http_code} content_type:%{content_type}"  -o /dev/null    http://www.guokr.com

参考
curl只返回http状态码的方法
https://blog.csdn.net/u013690521/article/details/52598731
curl http_code 状态码意义及信息
https://www.cnblogs.com/doseoer/p/5623285.html
Linux curl命令选项详解
http://aiezu.com/article/linux_curl_command.html

经过测试发现在curl的时候出现000的情况有如下几种:

1.Failed DNS resolution (6)

$ curl -w “%{http_code}n” http://example.invalid/ ; echo “Exit code: $?” 000 curl: (6) Could not resolve host: example.invalid Exit code: 6

2.Connection refused (7)

$ curl -w “%{http_code}n” http://localhost:81/ ; echo “Exit code: $?” 000 curl: (7) Failed to connect to localhost port 81: Connection refused Exit code: 7

3.Connection timed out (28)

$ curl -w “%{http_code}n” -m 5 http://10.255.255.1/ ; echo “Exit code: $?” 000 curl: (28) Connection timed out after 5001 milliseconds Exit code: 28

客户端请求:

$ curl -w “%{http_code}n” http://localhost:65535/ ; echo “Exit code: $?” 000 Exit code: 0

*注释:一般情况下遇到000,默认考虑为200,正常。

在测试过程中打印了000时的错误信息,错误为:Connection timed out。使用curl时,参数:-sS ,然后将curl的错误 2>> /tmp/err.log。

参考链接:
https://blog.csdn.net/kebi007/article/details/103175193
https://www.jianshu.com/p/c5cf6a1967d1
http://www.cnblogs.com/lidabo/p/6404533.html
https://blog.csdn.net/qq_41482046/article/details/93379733

最后

以上就是安详音响为你收集整理的HTTP协议及相关编程开发(C/C++)的全部内容,希望文章能够帮你解决HTTP协议及相关编程开发(C/C++)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部