【Linux】http 协议

打印 上一主题 下一主题

主题 1988|帖子 1988|积分 5964

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
目次

一、http协议
(一)http 协议的概念
(二)URL的构成
(三)urlencode 和 urldecode
二、http 的协议格式
(一)http 哀求方法
(二)http 响应状态码
(三)http 常见的响应报头
三、http 协议客户端和服务器通讯过程
(一)应用层如何保证将哀求或响应完备读取完了?
(二)http如何进行序列化和反序列化
(三)通讯全过程
1、启动服务器
2、工具类
2、分析哀求报文
3、发送响应报文
四、http 会话保持


一、http协议

(一)http 协议的概念

        上节我们提到可以自定协议,但是面临一些复杂的场景单靠自定协议是很难满意需求的。实际上已经有一些现成且好用的应用层协议,http 超文本传输协议就是其中之一。
(二)URL的构成

        URL即我们平时常称的网址。

        ip会标识一台网络主机,我们通过在浏览器中输入网址就可以访问该服务器,从指定的文件路径下找到用户哀求的文件返回给用户。
(三)urlencode 和 urldecode

        对于URL而言,在浏览器中其并不是完全明文显式的,比方:

        我们可以看到当我们搜索 C++ 时, URL中不是显式的C++,而是 C%2B%2B 的形式,这是由于在http协议对于URL中的特殊字符,必须将其进行转义。
   转义规则:
          一个字节是八个比特位,从中间分别左右各4位(不足4位直接处置惩罚),将左右4位分别转为16进制,将两位组合在一起后前面加上%便编码成%XY格式。
  二、http 的协议格式

(一)http 哀求方法

        本文只介绍两种常用的哀求方法:GET和POST。
方法说明支持的HTTP协议版本
GET获得资源1.0、1.1
POST传输实体主题1.0、1.1
        虽然它们都是客户端向服务器发出的哀求方法,但是二则略有不同。

        针对同一份前端表单form,当不同的哀求方法时,浏览器会将执行不同的动作:
   1、GET方法通过URL通报参数。比方上例中,当我们利用GET方法处置惩罚表单时,浏览器会将我们的表单内容拼接为URL发送给服务器,http://ip::port/XXX?key=value。利用URL进行传参注定了参数不能过大,当传输数据过大时利用GET方法哀求就不合适了;
  2、 POST方法则是通过http哀求正文通报参数的,对于正文数据巨细没有限定,适合通报一些大型文件。
  3、POST方法相较于GET方法更加私密,GET方法通过URL通报参数,所以通报的数据可以被直接看到。虽然POST方法比GET方法更私密,但二者实际都是不安全的,如果需要加密安全的话得利用https协议。
  (二)http 响应状态码

        https协议的状态码:
类别原因短语
1XXInformational(信息状态码) 接收的哀求正在处置惩罚
2XXSuccess(成功状态码)哀求正常处置惩罚完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成哀求
4XXClient Error(客户端错误状态码)服务器无法处置惩罚哀求
5XXServer Error(服务器错误状态码)服务器处置惩罚哀求堕落
        常见错误码:
   2XX:
  

  • 200 OK:哀求成功
  • 201 Created:哀求已经被实现,资源已经被创建。
  • 204 No Content:哀求成功,但响应报文不含实体的主体部门。
  3XX:
  

  • 301 Moved Permanently:永久性重定向
  • 302 Found:临时性重定向
  • 307 Temporary Redirect:临时性重定向
  4XX:
  

  • 400 Bad Request:哀求报文存在语法错误
  • 401 Unauthorized:未经授权,需要身份验证
  • 403 Forbidden:服务器拒绝哀求
  • 404 Not Found:服务器无法找到哀求的资源
  5XX:
  

  • 500 Internal Server Error:服务器内部错误
  • 502 Bad Gateway:网关错误
  • 503 Service Unavailable:服务器临时无法处置惩罚哀求
  • 504 Gateway Timeout:网关超时
  (三)http 常见的响应报头

   

  • Content-Type:指定响应体的MIME范例,比方text/html表示HTML文本,image/jpeg表示JPEG图片等。
  • Content-Length:指定响应体的长度,单位为字节
  • Host:客户端告知服务器, 所哀求的资源是在哪个主机的哪个端口上
  • User-Agent:声明用户的操作系统和浏览器版本信息
  • referer:当前页面是从哪个页面跳转过来的
  • location:搭配3xx状态码利用, 告诉客户端接下来要去那里访问
  • cookie:用于在客户端存储少量信息. 通常用于实现会话的功能
  三、http 协议客户端和服务器通讯过程


(一)应用层如何保证将哀求或响应完备读取完了?

        首先对于哀求行、哀求报头、状态行和响应报头都是按照 \r\n 为行分隔符,因此可以读取完备的一行。而报头与正文之间也存在着一个分隔符,因此可以区分哀求报头是否读取完备。而哀求报头中存在着 Content-Length 字段,其记录了正文的长度,因此应用层可以完备地读取哀求正文或响应正文,从而保证了应用层可以完备地读取一个完备的哀求或响应。
(二)http如何进行序列化和反序列化

        上节我们自界说协议的时候是需要对哀求和响应进行序列化和反序列化的,那么 http 协议是如何进行需要序列化和反序列化呢?实际 http 协议本身无需用户关注序列化和反序列化,直接发送即可,而对于正文部门,如果有需要用户可以自界说序列化和反序列化方案。
(三)通讯全过程

1、启动服务器

  1.     void httpHandler(int fd, func_t func)
  2.     {
  3.         // 读取数据
  4.         char buffer[1024];
  5.         ssize_t n = recv(fd, buffer, sizeof(buffer) - 1, 0);
  6.         if (n >= 0)
  7.         {
  8.             buffer[n] = 0;
  9.             Request req;
  10.             Response resp;
  11.             req.parse(buffer);
  12.             func(req, resp);
  13.             send(fd, resp.outbuffer.c_str(), resp.outbuffer.size(), 0);
  14.         }
  15.     }
  16.     void start(func_t func)
  17.     {
  18.         while (1)
  19.         {
  20.             signal(SIGCHLD, SIG_IGN);
  21.             sockaddr_in addr;
  22.             socklen_t len = sizeof(addr);
  23.             int socket = accept(_fd, (struct sockaddr *)&addr, &len);
  24.             if (socket == -1)
  25.             {
  26.                 cerr << "accept failure : " << strerror(errno) << endl;
  27.                 continue;
  28.             }
  29.             pid_t pid = fork();
  30.             if (pid == 0)
  31.             {
  32.                 close(_fd);
  33.                 httpHandler(socket, func);
  34.                 close(socket);
  35.                 exit(0);
  36.             }
  37.             close(socket);
  38.         }
  39.     }
复制代码
2、工具类

  1. #include <iostream>
  2. #include <string>
  3. #include <fstream>
  4. using namespace std;
  5. class Util
  6. {
  7. public:
  8.     static string getLine(string &buffer, const string &sep)
  9.     {
  10.         auto index = buffer.find(sep);
  11.         if (index == string::npos)
  12.             return "";
  13.         string ret = buffer.substr(0, index);
  14.         buffer.erase(0, index);
  15.         return ret;
  16.     }
  17.     static bool readFile(const string &text, char *buffer, int size)
  18.     {
  19.         fstream in(text, ios_base::binary | ios_base::in);
  20.         if (!in.is_open())
  21.             return false;
  22.         in.read(buffer, size);
  23.         in.close();
  24.         return true;
  25.     }
  26. };
复制代码
2、分析哀求报文

  1. class Request
  2. {
  3. public:
  4.     Request() {}
  5.     ~Request() {}
  6.     void parse(const string &in)
  7.     {
  8.         inbuffer = in;
  9.         string firstLine = Util::getLine(inbuffer, SEP);
  10.         stringstream s(firstLine);
  11.         s >> method >> url >> httpversion;
  12.         path = DEFAULT_PATH;
  13.         path += url;
  14.         if (path[path.size() - 1] == '/')
  15.             path += HOME_PAGE;
  16.         else
  17.             path += ".html";
  18.         struct stat st;
  19.         int ret = stat(path.c_str(), &st);
  20.         if (ret == 0)
  21.             size = st.st_size;
  22.         else
  23.             size = -1;
  24.     }
  25. public:
  26.     string inbuffer;
  27.     string method;
  28.     string url;
  29.     string path;
  30.     string httpversion;
  31.     string suffix;
  32.     string parm;
  33.     int size;
  34. };
复制代码
3、发送响应报文

  1. void Get(const Request &req, Response &resp)
  2. {
  3.     cout << "----------------------http recv start---------------------------" << endl;
  4.     cout << req.inbuffer << std::endl;
  5.     std::cout << "method: " << req.method << std::endl;
  6.     std::cout << "url: " << req.url << std::endl;
  7.     std::cout << "httpversion: " << req.httpversion << std::endl;
  8.     std::cout << "path: " << req.path << std::endl;
  9.     cout << "----------------------http recv end---------------------------" << endl;
  10.     cout << "----------------------http send start---------------------------" << endl;
  11.     resp.outbuffer += "HTTP/1.1 200 OK\r\n";
  12.     // resp.outbuffer += "HTTP/1.1 302 Found\r\n";
  13.     resp.outbuffer += "Content-Type: text/html\r\n";
  14.     // resp.outbuffer += "Location:https://blog.csdn.net/Sweet_0115?spm=1000.2115.3001.5343\r\n";
  15.     resp.outbuffer += "\r\n";
  16.     string body;
  17.     body.resize(req.size + 1);
  18.     if (!Util::readFile(req.path, (char *)body.c_str(), body.size()))
  19.         !Util::readFile("./wwwroot/404.html", (char *)body.c_str(), body.size());
  20.     cout << "test : -----------" << req.path << endl;
  21.     // cout << body << endl;
  22.     resp.outbuffer += body;
  23.     cout << resp.outbuffer << endl;
  24.     cout << "----------------------http send end---------------------------" << endl;
  25. }
复制代码
四、http 会话保持

        当我们打开CSDN登录后,即使我们关闭了浏览器,短期内我们再打开CSDN仍然不需要重复登录。同样的,我们在CSDN内进行网页跳转时,也不需要再重复登录。http 协议是无状态的,那么浏览器是怎么做到网页跳转时用户不需要重复登录呢?
        这实际就是会话保持,http哀求是无状态的,也就是以上功能并不是 http 提供的,而是session和cookie提供的。
        当用户首次登录时,浏览器会将用户的账号和暗码生存在cookie文件里,当用户近期再次访问该网站或在网站内进行跳转时,浏览器会自动将cookie文件里的数据推送给服务器,从而不需要用户再次登录。比方当我们利用软件观看一些会员视频时,利用以上机制可以鉴权进行身份判定。
        但以上方式实际很不安全,比方一些不法分子可以通过挟制 http哀求 从而获取到用户的账号和暗码,所以以上机制是很伤害的。
        实际当用户登录后,服务器会为用户建立会话(session),其会生存用户的信息,同时会返回给浏览器 session id。当用户近期再次访问网站或再网站内进行跳转时,浏览器则向服务器发送 session id,而服务器则通过该 session id 进行身份鉴权判定。

        但实际以上机制仍存在风险,不法分子仍然可以通过挟制 http 哀求获取 session id,通过该id仍然可以向服务器伪造哀求,但相比于第一种方案,至少用户的账户暗码信息没有丢失。上述方案也可以共同别的机制,比方短信验证或人脸识别保障信息安全,比方当账号突然被异地登录(用户信息泄漏),服务器检测后使 session id 失效并令用户重新进行验证登录,一定程度上保护了用户的信息安全。
        http哀求并不安全,如果有安全防护需求必须得利用https协议。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

三尺非寒

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表