認識http的方法、Header、狀態碼以及簡單實現一個http的業務邏輯

文章目錄

  • http的方法
  • http狀態碼
  • http重定向
  • http常見Header
  • 實現簡單業務邏輯
    • Protocol.hpp
    • Util.hpp
    • Server.hpp
    • Server.cc
  • 效果

http的方法

方法說明支持的HTTP版本
GET獲取資源1.0/1.1
POST傳輸實體主體1.0/1.1
PUT傳輸文件1.0/1.1
HEAD獲得報文首部1.0/1.1
DELETE刪除文件1.0/1.1
OPTIONS詢問支持方法1.1
TRACE追蹤路徑1.1
CONNECT要求用隧道協議連接代理1.1
LINK建立和資源之間的聯系1.0
UNLINE斷開連接關系1.0

其中最為常見的請求方法為:GET POST

事實上,瀏覽器向服務器進行數據提交時,本質是前端通過form表單提交的,瀏覽器會自動將form表單中的內容轉換為GET/POST的方法請求

例如在QQ的網址上會有登陸框,查看登陸框的源代碼就會發現有form表單

image-20230808141948402

如果輸入了賬號密碼之后點擊了登陸按鈕,瀏覽器就會將賬號和密碼根據指定的GET或者POST方法發送給服務器。

其中兩者的區別有:

  1. GET方法會將獲取到的數據作為參數直接通過url 傳遞,也就是說GET方法會在url 上直接顯示出數據,格式為:http://ip:port/XXX/YY?name=value&name2=value2。會直接暴露出數據
  2. POST方法不是通過url 傳遞數據,而是直接向請求的正文里提交數據。也就是說參數會存在在正文里,服務器再從正文里提取參數
  3. 因為GET方法是再url中直接傳遞參數,所以參數不能太大
  4. POST在正文傳遞參數,所以可以參數很大

需要注意的是

雖然POST方法不會暴露數據,但是并不意味著就是安全的。私密 != 安全。

如果要談到安全,那就必須要加密,加密內容屬于https協議

http狀態碼

類別原因
1XXinformational - 信息性狀態碼接受的請求正在處理
2XXsuccess - 成功狀態碼請求正常處理完畢
3XXredirection - 重定向狀態碼需要進行附加操作以完成請求
4XXclient error - 客戶端錯誤狀態碼服務器無法處理請求
5XXserver error - 服務端錯誤狀態碼服務器處理請求出錯

其中最常見的就是 404 網頁不存在

200 代表OK,404 Not Found,403 Forbiden,302 Redirect 重定向,504 Bad Gateway

http重定向

要實現重定向其實很簡單,將狀態碼修改為307代表重定向,然后在正文里加入重定向的網址即可,這樣向服務器請求后,服務器就會將處理的請求重定向到指定的網址

// 服務端處理的回調函數
bool func(const HttpRequest &req, HttpResponse &res)
{// 打印方便調試查看接收到的數據是否正確cout << "---------------http--------------" << endl;cout << req._inbuffer;cout << "_method: " << req._method << endl;cout << " _url: " << req._url << endl;cout << " _httpversion: " << req._httpversion << endl;cout << " _path: " << req._path << endl;cout << " _suffix: " << req._suffix << endl;cout << " _size: " << req._size << endl;cout << "---------------end---------------" << endl;// 狀態行// string resline = "HTTP/1.1 200 OK\r\n";string resline = "HTTP/1.1 307 Temporary Redirect\r\n";// 響應報頭// 需要注意正確的給客戶端返回資源,圖片是圖片,網頁是網頁string rescontet = Util::suffixToDesc(req._suffix);// 添加資源長度到報頭rescontet += "Content-Length: ";rescontet += to_string(req._size);rescontet += "\r\n";// 添加重定向rescontet += "Location: https://www.qq.com/\r\n";// 空行string resblank = "\r\n";// 響應正文string body;// 判斷資源是否存在,不存在就返回錯誤狀態碼 - 404if (!Util::FileIsNo(req._path, &body)){Util::FileIsNo(errorhtml, &body);}// 寫回響應的數據,后續要發送回客戶端res._outbuffer += resline;res._outbuffer += rescontet;res._outbuffer += resblank;res._outbuffer += body;return true;
}

http常見Header

名稱意義
Content-Type數據類型(text/html等)
Content-LengthBody的長度
Host客戶端告知服務器, 所請求的資源是在哪個主機的哪個端口上
User-Agent聲明用戶的操作系統和瀏覽器版本信息
referer當前頁面是從哪個頁面跳轉過來的
location搭配3xx狀態碼使用, 告訴客戶端接下來要去哪里訪問 – 重定向
Cookie用于在客戶端存儲少量信息. 通常用于實現會話(session)的功能

實現簡單業務邏輯

代碼里涉及html代碼,不詳細講解

由于服務器較弱,所以圖片獲取直接從網址獲取,不從服務器讀取

需要注意,一個網頁看到的結果,可能是有多個資源組合而成,例如有網頁,圖片,視頻等。所以要獲取一張完整的網頁效果需要瀏覽器發送多次請求,那么服務器就要根據請求的類型不同對響應正文處理的方式要指明Content-Type的類型。例如網頁為“text/html”,jpg格式的圖片為“image/jpeg”,不同的格式可自行搜索

判斷格式的方法可以根據 url 中資源的后綴進行判斷

以下代碼均有注釋:

Protocol.hpp

請求響應類

因為瀏覽器會自動處理收到的響應報文,所以不需要編寫處理方法只需要將響應報文發送回瀏覽器即可

#pragma once#include <iostream>
#include <string>
#include <sstream>
#include "Util.hpp"using namespace std;// 定義分隔符
#define sep "\r\n"
#define default_root "./wwwroot"
#define home_page "index.html"
#define errorhtml "./wwwroot/404.html"// 請求
class HttpRequest
{
public:string _inbuffer; // 接收請求數據string _method; // 處理數據方法的名稱string _url; // urlstring _httpversion; //  http協議版本string _path; // 查找資源的路徑string _suffix;// 資源后綴int _size;//資源長度HttpRequest(){}// 處理收到的數據// 添加默認路徑void parse(){// 拿到第一行string line = Util::GetOneLine(_inbuffer, sep);if(line.empty())return;cout << "line: " << line << endl;// 拿到第一行中的三個字段stringstream ss(line);ss >> _method >> _url >> _httpversion;// 添加默認路徑_path = default_root;_path += _url;// 如果url為/ 則添加默認路徑if(_path[_path.size() - 1] == '/')_path += home_page;// 獲取資源的后綴auto pos = _path.rfind(".");if(pos == string::npos)_suffix = ".html";else_suffix = _path.substr(pos);// 獲取到長度_size = Util::GetLen(_path);}};// 響應
class HttpResponse
{
public:string _outbuffer;
};

Util.hpp

工具類,將共有的方法定義同個類,方便調用

#pragma once#include <iostream>
#include <string>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>using namespace std;class Util
{
public:// 提取并刪除首行// 讀到的首行并不需要處理static string GetOneLine(string &inbuffer, const string &sep){auto pos = inbuffer.find(sep);if (pos == string::npos)return "";string sub = inbuffer.substr(0, pos);inbuffer.erase(0, sub.size() + sep.size());return sub;}// 判斷請求的資源是否存在static bool FileIsNo(const string resource, string *out){ifstream in(resource);// 打開文件失敗說明資源不存在if (!in.is_open())return false;string line;while (getline(in, line))*out += line;in.close();return true;}// 根據后綴指明響應報頭類型static string suffixToDesc(const string &suffix){string st = "Content-Type: ";if (suffix == ".html")st += "text/html";else if (suffix == ".jpg")st += "image/jpeg";st += "\r\n";return st;}// 獲取資源的長度static int GetLen(const string &path){struct stat s;int n = stat(path.c_str(), &s);if(n == 0)return s.st_size;return -1;}
};

Server.hpp

#pragma once#include "Protocol.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <sys/wait.h>
#include <unistd.h>using func_t = function<bool(const HttpRequest &, HttpResponse &)>;class Server
{
public:Server(func_t func, uint16_t &port): _port(port), _func(func){}void Init(){// 創建負責監聽的套接字 面向字節流_listenSock = socket(AF_INET, SOCK_STREAM, 0);if (_listenSock < 0)exit(1);// 綁定網絡信息struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;if (bind(_listenSock, (struct sockaddr *)&local, sizeof(local)) < 0)exit(3);// 設置socket為監聽狀態if (listen(_listenSock, 5) < 0)exit(4);}// 服務端讀取處理請求方法void HttpHandler(int sock){// 確保讀到完整的http請求char buffer[4096];size_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);HttpRequest req;HttpResponse res;if (n > 0){buffer[n] = 0;req._inbuffer = buffer;// 處理讀到的數據req.parse();// 調用回調方法反序列化請求并得到響應結果和序列化響應結果_func(req, res);// 發回客戶端send(sock, res._outbuffer.c_str(), res._outbuffer.size(), 0);}}void start(){while (1){// server獲取建立新連接struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));socklen_t len = sizeof(peer);// 創建通信的套接字// accept的返回值才是真正用于通信的套接字_sock = accept(_listenSock, (struct sockaddr *)&peer, &len);if (_sock < 0)continue;cout << "sock: " << _sock << endl;// 利用多進程實現pid_t id = fork();if (id == 0) // child{close(_listenSock);// 調用方法包括讀取、反序列化、計算、序列化、發送HttpHandler(_sock);close(_sock);exit(0);}close(_sock);// fatherpid_t ret = waitpid(id, nullptr, 0);}}private:int _listenSock; // 負責監聽的套接字int _sock;       // 通信的套接字uint16_t _port;  // 端口號func_t _func;
};

Server.cc

#include "Server.hpp"
#include <memory>// 輸出命令錯誤函數
void Usage(string proc)
{cout << "Usage:\n\t" << proc << " local_ip local_port\n\n";
}// 服務端處理的回調函數
bool func(const HttpRequest &req, HttpResponse &res)
{// 打印方便調試查看接收到的數據是否正確cout << "---------------http--------------" << endl;cout << req._inbuffer;cout << "_method: " << req._method << endl;cout << " _url: " << req._url << endl;cout << " _httpversion: " << req._httpversion << endl;cout << " _path: " << req._path << endl;cout << " _suffix: " << req._suffix << endl;cout << " _size: " << req._size << endl;cout << "---------------end---------------" << endl;// 狀態行string resline = "HTTP/1.1 200 OK\r\n";// string resline = "HTTP/1.1 307 Temporary Redirect\r\n";// 響應報頭// 需要注意正確的給客戶端返回資源,圖片是圖片,網頁是網頁string rescontet = Util::suffixToDesc(req._suffix);// 添加資源長度到報頭rescontet += "Content-Length: ";rescontet += to_string(req._size);rescontet += "\r\n";// // 添加重定向// rescontet += "Location: https://www.qq.com/\r\n";// 空行string resblank = "\r\n";// 響應正文string body;// 判斷資源是否存在,不存在就返回錯誤狀態碼 - 404if (!Util::FileIsNo(req._path, &body)){Util::FileIsNo(errorhtml, &body);}// 寫回響應的數據,后續要發送回客戶端res._outbuffer += resline;res._outbuffer += rescontet;res._outbuffer += resblank;res._outbuffer += body;return true;
}int main(int argc, char *argv[])
{// 啟動服務端不需要指定IPif (argc != 2){Usage(argv[0]);exit(1);}uint16_t port = atoi(argv[1]);unique_ptr<Server> server(new Server(func, port));// 服務端初始化server->Init();// 服務端啟動server->start();return 0;
}

效果

在此就不寫出html的文件了,看著效果能夠實現即可

可以看到瀏覽器向服務器發送請求,服務器返回響應,響應里就包括了自己編寫的html文件,所以瀏覽器處理后就顯示出了自己的網頁

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/34694.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/34694.shtml
英文地址,請注明出處:http://en.pswp.cn/news/34694.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【ts】【cocos creator】excel表格轉JSON

需要將表格導出為text格式放到項目resources/text文件夾下 新建場景&#xff0c;掛載到Canvas上運行 表格文件格式&#xff1a; 保存格式選text tableToJson : import CryptoJS require(./FileSaver);const { ccclass, property } cc._decorator;ccclass export default c…

SpringBoot案例-部門管理-新增

根據頁面原型&#xff0c;明確需求 頁面原型 需求 閱讀接口文檔 接口文檔鏈接如下&#xff1a; 【騰訊文檔】SpringBoot案例所需文檔 https://docs.qq.com/doc/DUkRiTWVaUmFVck9N 思路分析 前端在輸入要新增的部門名稱后&#xff0c;會以JSON格式將數據傳入至后端&#xf…

SpringBoot 3.x整合Fluent Mybatis極簡流程

此為基礎配置&#xff0c;不包括其他高級配置&#xff0c;需要其他高級配置請查閱官方文檔&#xff1a;[fluent mybatis特性總覽 - Wiki - Gitee.com](https://gitee.com/fluent-mybatis/fluent-mybatis/wikis/fluent mybatis特性總覽) 版本信息 Spring Boot 版本&#xff1a…

C語言創建目錄(文件夾)之mkdir

一、mkdir 說明&#xff1a;創建目錄。 頭文件庫&#xff1a; #include <sys/stat.h> #include <sys/types.h>函數原型&#xff1a; int mkdir(const char *pathname, mode_t mode);mode方式&#xff1a;可多個權限相或&#xff0c;如0755表示S_IRWXU | S_IRGRP…

undefined reference to `dlopen‘ ‘SSL_library_init‘ `X509_certificate_type‘

使用Crow的時候需要注意crow依賴asio依賴OpenSSL&#xff0c;asio要求1.22以上版本&#xff0c;我使用的是1.26.0&#xff1b; 這個版本的asio要求OpenSSL是1.0.2&#xff0c;其他版本我得機器上編不過&#xff0c;ubuntu上默認帶的OpenSSL是1.1.1; 所以我下載了OPENSSL1.2.0重…

MySQL高階知識點(一)一條SQL【更新】語句是如何執行的

一條SQL【更新】語句是如何執行的 首先&#xff0c;可以確定的說&#xff0c;【查詢】語句的那一套流程&#xff0c;【更新】語句也是同樣會走一遍&#xff0c;與查詢流程不一樣的是&#xff0c; 更新語句涉及到【事務】&#xff0c;就必須保證事務的四大特性&#xff1a;ACID&…

項目介紹:《WeTalk》網頁聊天室 — Spring Boot、MyBatis、MySQL和WebSocket的奇妙融合

目錄 引言&#xff1a; 前言&#xff1a; 技術棧&#xff1a; 主要功能&#xff1a; 功能詳解&#xff1a; 1. 用戶注冊與登錄&#xff1a; 2. 添加好友 3. 實時聊天 4. 消息未讀 5. 刪除聊天記錄 6. 刪除好友 未來展望&#xff1a; 項目地址&#xff1a; 結語&am…

【redis 3.2 集群】

目錄 一、Redis主從復制 1.概念 2.作用 2.1 數據冗余 2.2 故障恢復 2.3 負載均衡 2.4 高可用 3.缺點 4.流程 4.1 第一步 4.2 第二步 4.3 第三步 4.4 第四步 5.搭建 5.1 主 5.2 從 6.驗證 二、Reids哨兵模式 1.概念 2.作用 2.1 監控 2.2 自動故障轉移 2.…

分布式應用:Zabbix監控Nginx

目錄 一、理論 1.Zabbix監控Nginx 二、實驗 1.Zabbix監控Nginx部署 三、問題 1.重啟zabbix客戶端失敗 2.zabbix服務端測試客戶端nginx狀態失敗 3.nginx啟動失敗 4.權限不夠 一、理論 1.Zabbix監控Nginx &#xff08;1&#xff09;環境 zabbix服務端&#xff1a;192.1…

Tomcat線程池原理

1. 一個 SpringBoot 項目能同時處理多少請求&#xff1f;tomcat容器&#xff0c; 200 次。 2. 怎么來的&#xff1f; 而點擊這些線程&#xff0c;查看其堆棧消息&#xff0c;可以看到 Tomcat、threads、ThreadPoolExecutor 等關鍵字 基于“短時間內有 200 個請求被立馬處理…

分類預測 | Python實現LR邏輯回歸多輸入分類預測

分類預測 | Python實現LR邏輯回歸多輸入分類預測 目錄 分類預測 | Python實現LR邏輯回歸多輸入分類預測基本介紹模型描述源碼設計學習小結參考資料基本介紹 邏輯回歸是一種廣義線性的分類模型且其模型結構可以視為單層的神經網絡,由一層輸入層、一層僅帶有一個sigmoid激活函數…

設計模式十二:享元模式(Flyweight Pattern)

當我們需要創建大量相似對象時&#xff0c;享元模式可以幫助我們節省內存空間和提高性能。該模式通過共享相同的數據來減少對象的數量。 在享元模式中&#xff0c;有兩種類型的對象&#xff1a;享元&#xff08;Flyweight&#xff09;和非享元&#xff08;Unshared Flyweight&a…

Postman下載教程

目錄 下載 安裝 注意事項 看到很多小伙伴在問 Postman 下載的相關問題&#xff0c;花時間整理了下&#xff0c;下面教新入門的小伙伴如何去下載 Postman。 開始前我們可以先了解下&#xff1a;Postman 簡介 下載 第一步&#xff1a;進入 Postman 官網 首先&#xff0c;我…

maven打包上傳到私有倉庫的步驟

maven打包上傳到私有倉庫的步驟 一、pom.xml引入二、Maven的settings.xml三、pom.xml中添加源碼插件四、執行發布命令 先準備私庫地址&#xff1a; http://localhost:8081/nexus3/repository/maven-releases http://localhost:8081/nexus3/repository/maven-snapshots 假如現需…

如何在Vue表單處理中實現表單字段的文件下載

Vue.js 是一種流行的JavaScript框架&#xff0c;用于構建用戶界面。在Vue應用中&#xff0c;我們經常需要處理表單操作&#xff0c;其中一個常見需求是實現文件下載。以下介紹如何在Vue表單處理中實現表單字段的文件下載&#xff0c;大家共同交流。 一、使用HTML的a標簽實現文…

Java單例模式詳解(五種實現方式)

1、什么是單例模式&#xff1f; Java單例模式是一種設計模式&#xff0c;用于確保一個類只有一個實例&#xff0c;并提供全局訪問點以獲取該實例。它通常用于需要共享資源或控制某些共享狀態的情況下。 例如&#xff1a; 一個日志記錄器&#xff08;Logger&#xff09;。在一個…

二級考python和c語言哪個好,計算機二級python和c

大家好&#xff0c;小編來為大家解答以下問題&#xff0c;二級python和二級c語言哪個更吃香一些&#xff0c;二級python和二級c語言哪個更吃香一點&#xff0c;今天讓我們一起來看看吧&#xff01; 計算機二級貌似只是在校園里的自嗨&#xff0c;出來工作后并沒有覺得這個證書有…

JavaScript+Asp.Net MVC5同時下載多個文件

前端同時啟動多個下載任務&#xff08;但是沒有做壓縮包下載&#xff09; 前端JavaScript腳本&#xff1a; var idList [1,2,3];//要下載的列表 $.each(idList, function (index, item) {downloadURL("/File/GetPdf?id" item); });var count 0; var downloadUR…

LeetCode 21.合并兩個有序鏈表

文章目錄 &#x1f4a1;題目分析&#x1f4a1;解題思路&#x1f6a9;思路1: 歸并排序思想&#xff08;不使用帶哨兵衛的頭節點&#xff09;&#x1f514;接口源碼&#xff1a; &#x1f4a1;解題思路&#x1f6a9;思路2: 歸并排序思想&#xff08;使用帶哨兵衛的頭節點&#xf…

Ubuntu安裝JDK與IntelliJ IDEA

目錄 前言 Ubuntu 安裝 JDK 1、更新軟件包列表 2、安裝OpenJDK 3、驗證安裝 Ubuntu安裝IntelliJ IDEA 1、下載 IntelliJ IDEA 2、解壓縮 IntelliJ IDEA 安裝包 3、移動 IntelliJ IDEA 到安裝目錄 4、啟動 IntelliJ IDEA 前言 APT&#xff08;Advanced Package Tool&…