应用层协议HTTP
一、万维网
万维网www(World Wide Web)并非某种特殊的计算机网络。万维网是一个大规模的、联机式的信息储藏所,英文简称为 Web。万维网用链接的方法能非常方便地从因特网上的一个站点访问另一个站点(也就是所谓的"链接到另一个站点"),从而主动地按需获取丰富的信息。

- 万维网客户端和万维网服务器之间的通信协议:http(超文本传输协议)
- 万维网服务器如何标记万维网文档:url(统一资源定位符)
- 万维网客户端如何显示万维网文档:html(超文本标记语言)
二、URL
统一资源定位符URL是用来表示从因特网上得到的资源位置和访问这些资源的方法。URL给资源的位置提供一种抽象的识别方法,并用这种方法给资源定位。只要能够对资源定位,系统就可以对资源进行各种操作,如存取、更新、替换和查找其属性。
URL标准格式:<协议>://<主机>:<端口>/<路径>
https:

/:请求服务区主页

三、HTTP协议
应用层
HTTP协议:超文本传输协议
基于传输层TCP协议,端口80
HTTPS:SSL加密方式,默认端口443
万维网的工作过程

HTTP协议工作流程
HTTP报文


Request Headers (请求报文)
GET / HTTP/1.1\r\n
Host: news.sohu.com\r\n
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: keep-alive\r\n
Cookie: hideAddDesktop=true\r\n
Upgrade-Insecure-Requests: 1\r\n
\r\n
keep-alive:长连接,HTTP通信结束,保持一定时间的连接再断开;
close:短连接,HTTP通信结束,立即断开连接。
Response Headers(回复报文)
HTTP/1.1 200 OK\r\n
Date: Wed, 02 Sep 2026 07:20:15 GMT\r\n
Content-Type: text/html;charset=utf-8\r\n
Server: openresty\r\n
Vary: Accept-Encoding\r\n
Vary: Origin\r\n
Vary: Access-Control-Request-Method\r\n
Vary: Access-Control-Request-Headers\r\n
Set-Cookie: SUV=1788333615053odinavKw; Path=/; Domain=sohu.com; Max-Age=946080000; Expires=Fri, 25 Aug 2056 07:20:15 GMT; Secure; SameSite=None\r\n
Trace-Id: abdb6825d6664686b0cf6daf7b9f535e.124753.17883336150523913\r\n
Data-Source: \r\n
X-Content-Type-Options: nosniff\r\n
X-XSS-Protection: 0\r\n
S-REQ-ID: 17250949110141591456\r\n
S-REQ-TYPE: 0\r\n
X-Cache-Lookup: Cache Miss\r\n
Content-Encoding: gzip\r\n
Cache-Control: no-cache\r\n
Transfer-Encoding: chunked\r\n
X-NWS-LOG-UUID: 17250949110141591456\r\n
Connection: keep-alive\r\n
X-Cache-Lookup: Cache Miss\r\n
四、爬虫编写:
客户端流程:
- 建立TCP连接;
- 发送HTTP请求报文;
- 接受HTTP响应报文;
- 关闭HTTP链接。
公共
Request Headers
GET /?app=weather.today&cityNm=%E8%A5%BF%E5%AE%89&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json HTTP/1.1\r\n
Host: api.k780.com\r\n
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
\r\n
Response Headers
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 02 Sep 2026 09:19:29 GMT
Content-Type: application/json; charset=utf-8;
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
代码示例 :
基于 Linux 下 TCP 套接字编程实现简易 HTTP 客户端,先调用socket()创建流式套接字,填充服务端地址结构体后通过connect()连接指定 IP 的 80 端口,构造符合 HTTP1.1 规范的 GET 请求报文,使用send()向服务端发送请求,再循环调用recv()读取服务器返回的 HTTP 响应数据,将接收内容直接输出到标准输出,当recv返回 0 代表连接关闭时结束接收,最后关闭套接字完成通信;代码存在两处隐患:send_request与recv_respose函数缺少 return 返回值,且代码中填写的目标 IP 和 HTTP 请求里的 Host 域名不匹配,会导致服务器返回异常响应。
c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#define SER_IP "36.103.218.105"
#define SER_PORT 80
int socket_init()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("socket error");
return -1;
}
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(SER_PORT);
seraddr.sin_addr.s_addr = inet_addr(SER_IP);
socklen_t len = sizeof(seraddr);
int ret = connect(sockfd, (struct sockaddr *)&seraddr, len);
if(ret < 0)
{
perror("connect error");
return -1;
}
return sockfd;
}
int send_request(int sockfd)
{
char request_headers[] = "GET / HTTP/1.1\r\n"
"Host: news.sohu.com\r\n"
"User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n"
"Accept-Language: en-US,en;q=0.5\r\n"
"Connection: keep-alive\r\n"
"Upgrade-Insecure-Requests: 1\r\n"
"\r\n";
ssize_t size = send(sockfd, request_headers, sizeof(request_headers), 0);
if(size < 0)
{
perror("send request_headers error");
return -1;
}
}
int recv_respose(int sockfd)
{
char buff[1024];
while(1)
{
memset(buff, 0, sizeof(buff));
ssize_t size = recv(sockfd, buff, sizeof(buff), 0);
if(size < 0)
{
perror("recv error");
return -1;
}
if(0 == size)
{
printf("recv success\n");
break;
}
write(1, buff, size);
}
}
int main()
{
int sockfd = socket_init();
send_request(sockfd);
recv_respose(sockfd);
close(sockfd);
return 0;
}