Linux之Http协议分析以及cookie和session

Linux之Http协议分析以及cookie和session

  • 一.分析请求行与响应行
    • 1.1请求行
    • 1.1.1资源的URL路径
    • 1.1.2常见的方法
    • 1.2响应行
  • 二.cookie和session
    • 2.1cookie
    • 2.2session

一.分析请求行与响应行

在我们简单了解了请求和响应的格式以及模拟实现了请求和响应后我们已经可以通过网页来访问我们的服务器从而获得一些简单的信息,但是这些还只是http协议的冰山一角,今天我们还需要继续分析请求和响应中的首行从而来更了解http协议。

1.1请求行

请求行中一共分为三部分:方法+URL路径+版本号。其中版本号我们在上篇文章中已经谈过其中的内容也相对来说不那么重要,而方法我们也只要会用最常见的两种以及记住其余的大致作用即可但是URL路径却是我们最需要谈的。

1.1.1资源的URL路径

我们先来再看一下我们的请求行中存储的URL路径
在这里插入图片描述
这里的我只用了IP:端口号的方式在浏览器上访问服务器而这时URl路径显示的就只是一个/符号那么如果我在IP:端口号的基础上加上路径呢?那时候请求行中的URL路径会发生改改变吗?
在这里插入图片描述
我将路径改成了/a/b后很明请求行中的URL路径也发生了改变,就说明如果我们访问时在端口后不加上路径那么就会默认访问/路径下的资源,如果自己添加了路径就会访问该路径下的资源。可是问题是这个/是什么呢?为什么不添加路径就会默认访问该路径下的资源?

http协议规定的是如果我们不自己添加访问的路径,那么就会默认访问web根目录而web根目录通俗一点的话就是访问网址的首页那么具体是访问根目录下的哪个资源呢?其实我们默认访问的是/index.html。
可能大家会说我们模拟实现的代码里并没有什么index.html资源啊而且你说自己填路径和访问web根目录时访问的资源是不一样的那么为什么我们上面的图片里都是一样的helloworld呢?这是我们编写的代码的缘故我们现在并没有对URL路径加以分析而且一股脑的对于访问都塞一个一样的响应回去所以导致如此结果。

那么我们要如何区分URL路径而且那些不同路径下的资源又要怎么存放呢?
在Linux中一切皆文件所以大家很容易可以想到我们可以创建几个不同的文件来存放资源到时候只要我们对URL路径进行分析再让其去访问其中的内容即可。所以我们可以创建一共目录来存放这些不同路径下的资源,而这个目录在网络编程下一般都是设为wwwroot也可以是webroot。接下来我就来给大家模拟实现一下我们所说的这个方法。

// HttpProtocol.hpp
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>

const static std::string HttpSep = "\r\n";

// 默认访问的资源
const static std::string homepage = "index.html";
const static std::string wwwroot = "./wwwroot";

class HttpRequest
{
public:
    HttpRequest()
        : _blankline(HttpSep), _path(wwwroot)
    {
    }
    ~HttpRequest()
    {
    }
    bool Getline(std::string &request, std::string *line)
    {
        // 请求行\r\n请求报头\r\n空行\r\n请求正文
        // 在请求中查找HttpSep
        auto pos = request.find(HttpSep);
        if (pos == std::string::npos)
        {
            return false;
        }
        // 分割请求
        *line = request.substr(0, pos);
        request.erase(0, pos + HttpSep.size());
        return true;
    }
    bool Deserializa(std::string &request)
    {
        std::string line;
        // 判断是否只有请求行
        bool ok = Getline(request, &line);
        if (!ok)
        {
            return false;
        }
        _req_line = line;
        // 一行一行的分割请求
        while (true)
        {
            bool ok = Getline(request, &line);
            if (ok && line.empty())
            {
                // 如果分割行成功并且line中存储是空行
                // 说明request只剩下了正文(无论正文是否有内容)
                _req_content = request;
                break;
            }
            else if (ok && !line.empty())
            {
                // 如果分割成功并且line内有内容
                // 说明line中存储的是请求报头中的一行
                _req_header.push_back(line);
            }
            else
            {
                break;
            }
        }
        return true;
    }

    void DebugHttp()
    {
        std::cout << "_req_line:" << _req_line << std::endl;
        std::cout << "_req_header:" << std::endl;
        for (auto &line : _req_header)
        {
            std::cout << "---> " << line << std::endl;
        }
        std::cout << "_req_blank: " << _blankline << std::endl;
        std::cout << "_req_content: " << _req_content << std::endl;

        std::cout << "Method: " << _method << std::endl;
        std::cout << "url: " << _url << std::endl;
        std::cout << "path: " << _path << std::endl;
        std::cout << "http_version: " << _http_version << std::endl;
    }

    // 分析请求行
    void AnalyseReqline()
    {
        // 大家可以用find来查找空格之后再进行分割的方法
        // 但是我这里就使用C++中专门处理字符串的输入输出流stringstream
        // 使用sstream需要包含头文件<sstream>
        std::stringstream ss(_req_line);
        // 请求行:method path version
        // 而stringstream的插入会自动以空格为分割
        ss >> _method >> _url >> _http_version;

        // 如果_url为根目录就还需要添加默认的资源
        if (_url == "/")
        {
            _path += _url;
            _path += homepage;
        }
        else
        {
            // 不是根目录则直接加URL路径即可
            _path += _url;
        }
    }

    // 分析后缀
    void AnalyseSuffix()
    {
        // index.html我们只需要拿到.和其之后的字符即可
        auto pos = _path.rfind(".");
        if (pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".html";
        }
    }

    // 对资源文件做处理
    std::string GetFileContentHelper(const std::string &path)
    {
        // 因为是对文件做处理所以使用ifstream
        std::cout << "this1" << std::endl;
        std::cout << path << std::endl;
        std::ifstream in(path, std::ios::binary);
        std::cout << "this2" << std::endl;
        // 打开文件,失败返回""成功则读取其中内容
        if (!in.is_open())
        {
            std::cout << "this3" << std::endl;
            return "";
        }
        std::cout << "this4" << std::endl;

        std::string content;
        std::string line;
        // 一行一行的读取
        while (std::getline(in, line))
        {
            content += line;
        }
        in.close();
        return content;
    }

    std::string GetFileContent()
    {
        return GetFileContentHelper(_path);
    }

    void Analyse()
    {
        // 1.分析请求行
        AnalyseReqline();
        // 2.分析后缀
        AnalyseSuffix();
    }

    std::string GetUrl()
    {
        return _url;
    }

    std::string GetPath()
    {
        return _path;
    }

    std::string GetSuffix()
    {
        return _suffix;
    }

private:
    // 根据请求格式我们可以设计出四个变量
    std::string _req_line;                // 请求行
    std::vector<std::string> _req_header; // 请求报头
    std::string _blankline;               // 空行
    std::string _req_content;             // 请求正文

    // 分析请求行后
    std::string _method;       // 方法
    std::string _url;          // 路径
    std::string _http_version; // 版本

    // 分析URL后将其分为路径和后缀两部分
    // 因为资源有很多种类所以我们需要判别资源的种类再加以不同处理
    std::string _path;
    std::string _suffix;
};

// httpserver.cc
#include <iostream>
#include <memory>

#include "HttpProtocol.hpp"
#include "Tcpserver.hpp"

// 文件的后缀决定了文件的类型,http协议需要响应报头中包含正文的文件类型
std::string SuffixToType(const std::string &suffix)
{
    if (suffix == ".html" || suffix == ".htm")
    {
        return "text/html";
    }
    else if (suffix == ".png")
    {
        return "image/png";
    }
    else if (suffix == ".jpg")
    {
        return "image/jpeg";
    }
    else
    {
        return "Unknown";
    }
}

std::string HandleMethod(std::string request)
{
    HttpRequest http_req;
    http_req.Deserializa(request);
    http_req.Analyse();
    http_req.DebugHttp();

    std::string content = http_req.GetFileContentHelper(http_req.GetPath());

    if (!content.empty())
    {
        std::string httpstatusline = "Http/1.0 200 OK\r\n";
        std::string httpheader = "Content-Length: " + std::to_string(content.size()) + "\r\n"; // 正文的大小
        httpheader += "Content-Type: " + SuffixToType(http_req.GetSuffix()) + "\r\n";          // 正文的类型
        httpheader += "\r\n";

        std::string httpresponse = httpstatusline + httpheader + content;
        return httpresponse;
    }
    return "";
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "Usge:\n"
                  << argv[0] << " port" << std::endl;
        return 0;
    }
    uint16_t localport = std::stoi(argv[1]);

    std::unique_ptr<TcpServer> svr(new TcpServer(localport, HandleMethod));

    svr->Loop();
    return 0;
}
}

在这里插入图片描述

我们的资源有很多种类型,一般常见的就是.html,.png等等。对应.html文件的编写是我们前端人员的工作所以大家可以自行去搜索学习一下。
在这里插入图片描述

这是我们现在用浏览器访问服务器web根目录资源的样子,大家可以发现我们的图片加载不出来这是因为我们的图片在解析的时候是全二进制的但是我们如今使用的对资源文件做处理是针对于文本文件的如.html文件所以我们还需要将处理方法改进成通用方法才行。

// 对资源文件做处理
    std::string GetFileContentHelper(const std::string &path)
    {
        // 文本
        //  // 因为是对文件做处理所以使用ifstream
        //  std::ifstream in(path, std::ios::binary);
        //  // 打开文件,失败返回""成功则读取其中内容
        //  if (!in.is_open())
        //  {
        //      return "";
        //  }
        // std::string content;
        // std::string line;
        // // 一行一行的读取
        // while (std::getline(in, line))
        // {
        //     content += line;
        // }
        // in.close();
        // return content;

        // 通用方法
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            return "";
        }
        // 跳转到in的末尾
        in.seekg(0, in.end);
        // 将in的大小填入filesize中
        int filesize = in.tellg();
        // 跳转到in的开头
        in.seekg(0, in.beg);

        std::string content;
        // 设置content的大小
        content.resize(filesize);
        // 将in的内容填入到content中
        in.read((char *)content.c_str(), filesize);

        in.close();
        return content;
    }

在这里插入图片描述

1.1.2常见的方法

在我们了解常见的方法前我们需要先知道上网这个行为的本质是什么,本质就是我们从网上上获取资源或者我们向服务器传送参数也就是资源,而我们最常用的GET方法和POST方法就包含了这两方面。

  1. GET方法
    通常用来获取资源也可以通过URL地址来传参,但是传输的参数私密性不强。传参这个动作需要依靠我们html文件的表单来实现
    在这里插入图片描述
    那么我们向里面输入信息后URL地址会发生怎么样的变化呢?在这里插入图片描述
    那么我们如果向里面填写信息呢信息会被加入到URL里吗?
    在这里插入图片描述
    至于为什么私密性不强我想大家一眼就看出来了因为在URL地址中所有人都能看见当然私密性不强了。

  2. POST方法
    通常用来上传数据但是POST方法上传数据的形式和GET不同,POST方法不会将数据存在URL地址中而是存于请求正文中传给服务器,通过请求正文传参那么肉眼可见的POST传参的私密性会好一点。
    在这里插入图片描述

同时由于GET是利用URL传参所以会受到URL自身被规定的长度所限制但是POST方法则不会,虽然POST方法的私密性比GET方法好一点但是其实两者都不安全。那么我们想要我们传输的账号密码安全就必须经过加密和解密的过程这也就形成了我们之后的https协议。

至于其余的方法我就直接用别的博主写的来列给大家看看了因为都不是很重要

  1. HEAD
    获得报文首部,类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头。欲判断某个资源是否存在,我们通常使用GET,但这里用HEAD则意义更加明确。
    向服务器获取某些易过期或丢失大型文件时,可用HEAD方式查询资源是否存在。

  2. OPTIONS
    询问支持的方法客户端询问服务器可以提交哪些请求方法。这个方法很有趣,它用于获取当前URL所支持的方法。若请求成功,则它会在HTTP头中包含一个名为“Allow”的头,值是所支持的方法,如“GET, POST”。
    极少使用。

  3. PUT
    传输文件。从客户端向服务器传送的数据取代指定的文档的内容,即指定上传资源存放路径。这个方法比较少见。HTML表单也不支持这个。本质上来讲, PUT和POST极为相似,都是向服务器发送数据,但它们之间有一个重要区别,PUT通常指定了资源的存放位置,而POST则没有,POST的数据存放位置由服务器自己决定。

  4. PATCH
    局部更新文件,是对 PUT 方法的补充,用来对已知资源进行局部更新 。
    极少使用。

  5. DELETE
    删除文件。请求服务器删除指定的资源。
    基本上这个也很少见,不过还是有一些地方比如amazon的S3云服务里面就用的这个方法来删除资源。

  6. TRACE
    追踪路径,回显服务器收到的请求,客户端可以对请求消息的传输路径进行追踪,TRACE方法是让Web服务器端将之前的请求通信还给客户端的方法。主要用于测试或诊断。
    极少使用。

  7. CONNECT
    要求用隧道协议连接代理,HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL(安全套接层)和TLS(传输层安全)协议把通信内容加密后经网络隧道传输。
    极少使用。

原文链接:https://blog.csdn.net/demo_yo/article/details/123596028

1.2响应行

对应响应行的分析就简单多了我们只需要分析状态码即可,状态码也很好理解就是告诉你完成的情况或者有一些特殊情况。所以我直接给状态码贴给大家我拿其中比较典型的几个给大家说一说然后我们也还需要模拟实现一下不同状态码的情况。
在这里插入图片描述
一共五大类状态码分别以12345开头每大类中还需要细分,我就给每大类中典型的跟大家解释一下这样大家也对五种状态码有个概念。

  1. 信息状态码(1xx)
    信息状态码我们只需要记住100即可,100状态码出现的情况一般是当我们从客户端往服务器传输数据时过大服务器无法一次性接收完全,当服务器接收了一半之后就会传出100状态码来告诉客户端你可以继续上传数据了。所以100状态码就是继续的含义。
  2. 成功状态码(2xx)
    成功状态码我们需要记住200和204。200很简单就是告诉你请求被处理成功了而204也是告诉你请求被处理成功了但是没有结果返回。
  3. 重定向状态码(3xx)
    重定向状态码需要大家理解并且记住301和302分别是永久重定向和临时重定向。首先我们来解释一下什么是http里的重定向,我给大家举两个例子一个是当我们创建的网站过期了之后我们需要换IP地址换域名了但是用户只记得旧网站的网址另外一个是我们在各种的网站中会登入自己的账号有时候在登入账号后会自动条状到自己账号的主页。第一个需要我们在将旧网站重定向到新网站从而达成用户只要登入旧网站就会自动跳转到新网站上,第二个是如何完成的呢也就像我们刚刚展示表单时我们把登入按钮重定向到用户自己的主页上这样这要我们登入成功了就会自动跳转。从这两个例子中我们可以发现重定向的作用一般就是从一个网址跳转到另外一个网址上,并且这两个例子中的重定向还不一样第一个例子是永久重定向因为旧网站不用了过期了只用新网站现在,第二个例子是临时重定向我们只需要在当时让用户完成登入后跳转到主页即可。
  4. 客户端错误状态码(4xx)
    客户端错误状态码则需要大家记住403和404这两个即可。404状态码其实算这些状态码里比较常见的了,我们只需要访问一些不存在的网站就很容易得出这个状态码。在这里插入图片描述
    而403状态码则是我们如果访问了一些我们没有全新的网址就会出现。

这两个状态码是很好理解的但是比较难理解的是4xx状态码为什么叫做客户端错误状态码,明明是我访问你们服务器为什么变成我错了呢?其实从这两个状态码的名字里就能看出来一个是访问不存在的网址一个是访问没权限的网址,从服务器的角度上我明明有这么多页面可以给你看你偏偏找一个不存在的网址或者找一个你没权限的网址,我用心用力的给你服务你这不是给我找茬吗。所以这是用户自己作的妖当然就是客户端错误状态码了。

  1. 服务器错误状态码(5xx)
    这个状态码需要大家记住500和503,服务器错误状态码平时应该很少见因为我们如今使用的软件大多都是一些大厂发行的他们的服务器一般都是比较稳定的除了个别公司。500状态码的含义是服务器崩溃或者数据库崩溃导致页面无法加载出来,503状态码是服务器正在维护或者过载导致暂时无法处理请求。

在了解了这些状态码后我们也可以来模拟实现一下这些状态码对应的情况

const static std::string Space = " ";

// 响应
class HttpResponse
{
public:
    HttpResponse()
        : _version("HTTP/1.0"), _status_code(200), _status_code_desc("OK"), _blankline(HttpSep)
    {
    }
    ~HttpResponse()
    {
    }

    void SetCode(int status_code)
    {
        _status_code = status_code;
    }
    void SetDesc(std::string status_code_desc)
    {
        _status_code_desc = status_code_desc;
    }

    void MakeStatusLine()
    {
        _status_line = _version + Space + std::to_string(_status_code) + Space + _status_code_desc;
    }

    void Addheader(std::string header)
    {
        _resp_header.push_back(header);
    }

    void Addcontent(std::string content)
    {
        _resp_content = content;
    }

    std::string Serializa()
    {
        std::string response_str = _status_line;
        for (auto header : _resp_header)
        {
            response_str += header;
        }
        response_str += _blankline;
        response_str += _resp_content;
        return response_str;
    }

private:
    std::string _status_line;              // 状态行
    std::vector<std::string> _resp_header; // 响应报头
    std::string _blankline;                // 空行
    std::string _resp_content;             // 响应正文

    std::string _version;          // 版本
    int _status_code;              // 状态码
    std::string _status_code_desc; // 状态码解释
};

// Tcpserver.cc
#include <iostream>
#include <memory>

#include "HttpProtocol.hpp"
#include "Tcpserver.hpp"

// 文件的后缀决定了文件的类型,http协议需要响应报头中包含正文的文件类型
std::string SuffixToType(const std::string &suffix)
{
    if (suffix == ".html" || suffix == ".htm")
    {
        return "text/html";
    }
    else if (suffix == ".png")
    {
        return "image/png";
    }
    else if (suffix == ".jpg")
    {
        return "image/jpeg";
    }
    else
    {
        return "Unknown";
    }
}

std::string CodeToDesc(int code)
{
    if (code == 200)
    {
        return "OK";
    }
    else if (code == 301)
    {
        return "Moved Permanently";
    }
    else if (code == 307)
    {
        return "Temporary Redirect";
    }
    else if (code == 403)
    {
        return "Forbidden";
    }
    else if (code == 404)
    {
        return "Not Found";
    }
    else if (code == 500)
    {
        return "Internal Server Error";
    }
    else
    {
        return "Unknown";
    }
}

std::string HandleMethod(std::string request)
{
    HttpRequest http_req;
    http_req.Deserializa(request);
    http_req.Analyse();
    http_req.DebugHttp();

    int code = 200;

    std::string content = http_req.GetFileContentHelper(http_req.GetPath());
    if (content.empty())
    {
        code = 404;
        content = http_req.GetFile404();
    }

    HttpResponse response;

    // 设置状态码
    response.SetCode(code);
    // 设置状态码描述
    response.SetDesc(CodeToDesc(code));
    // 生成状态行
    response.MakeStatusLine();

    // 插入响应报头
    std::string content_len_str = "Content-Length: " + std::to_string(content.size()) + "\r\n"; // 正文的大小
    response.Addheader(content_len_str);
    std::string content_type_str = "Content-Type: " + SuffixToType(http_req.GetSuffix()) + "\r\n"; // 正文的类型
    response.Addheader(content_type_str);

    // 插入响应正文
    response.Addcontent(content);

    // 序列化
    return response.Serializa();
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "Usge:\n"
                  << argv[0] << " port" << std::endl;
        return 0;
    }
    uint16_t localport = std::stoi(argv[1]);

    std::unique_ptr<TcpServer> svr(new TcpServer(localport, HandleMethod));

    svr->Loop();
    return 0;
}

二.cookie和session

我们在学习了GET和POST方法后知道我们是可以通过请求正文给服务器传输信息的从而达成登入的操作但是不知道大家在日常使用中有没有发现我们只要登入了某个网站之后的一段时间我们就不需要再输入账号密码来登入了,这是为什么呢?
我们很容易就能想到一个答案:Http协议记住了我们的账号密码这样只要我们登入过一次之后就不用再登入了。但是这是错的这是因为Http协议是无状态无连接的,什么叫做无状态无连接呢也就是Http协议是不记住自己的历史的所以每次打开一个网站理论上是都是第一次打开因为http协议不记得你之前来过那不就是当第一次吗。这个问题也就导致了理论上我们每次都需要重新登入就算我们答应网站的公司也不答应啊,这样的操作不就很花费用户的时间和耐心也就会让网站的流量下降盈利也就下降了。所以针对这种情况延申出了两种解决方法:cookie和session,准确的来说session是在cookie的基础上改进了。

2.1cookie

想要解决这个问题其实很简单我们只需要在第一次登入的时候通过POST方法将账号密码传入到服务器中之后服务器再在响应报头中添加进去返回给浏览器,这样浏览器中就存有了你的账号密码之后每次再登入对应的网址的时候浏览器只要将你的账号密码通过请求报头传入到服务器让服务器查询是否有此用户即可。而cookie就是浏览器保存起来的报头形式的账号密码。
在这里插入图片描述
但是这样的解决方案依然有问题:浏览器保存的都是我真实的私密信息但是浏览器中的信息太过容易被盗取只要有人获得了我的私密信息就可以随意使用我的账号了。这就造成了用户的隐私安全问题。
在这里插入图片描述
我们现在使用的都是https协议所以cookie都是被加密过的但是在以前只用http协议时cookie信息是明晃晃的存在浏览器中的。

2.2session

所以有人为了避免这种问题将cookie改进成了session,而改进的地方就在于当服务器接收了来自浏览器POST的数据后它会通过这个数据生成一个结构体session和一个独一无二的sessionid并且这个session中还会存放用户的状态例如地理位置等等,之后就将账号密码再传回给浏览器而是将这个sessionid传给浏览器。浏览器只需要保存这个sessionid在下次登入的时候将sessionid传给服务器,服务器再进行查找判断即可。这样的好处是浏览器保存的就不是用户的真实隐私而是一串独特的sessionid并且在session中你不仅可以通过账号密码来判断用户是否合法还可以通过用户此次登入的地理位置和上一次的地理位置的距离来判断。
在这里插入图片描述
这样就解决了用户的隐私安全问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/967249.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue+element-ui简洁完美实现ju动漫网站

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.日漫 4.更多>排行榜 5.详情页 6.简单登陆页 三、源码实现 1.路由配置 2.首页 四、总结 一、项目介绍 本项目在线预览&#xff1a;点击访问 本项目为vue项目&#xff0c;以动漫为主题来设计元素&#xff…

协议-WebRTC-HLS

是什么&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09; 实现 Web 浏览器和移动应用程序之间通过互联网直接进行实时通信。允许点对点音频、视频和数据共享&#xff0c;而无需任何插件或其他软件。WebRTC 广泛用于构建视频会议、语音通话、直播、在线游…

本地部署DeepSeek-R1模型(新手保姆教程)

背景 最近deepseek太火了&#xff0c;无数的媒体都在报道&#xff0c;很多人争相着想本地部署试验一下。本文就简单教学一下&#xff0c;怎么本地部署。 首先大家要知道&#xff0c;使用deepseek有三种方式&#xff1a; 1.网页端或者是手机app直接使用 2.使用代码调用API …

有关网络安全的案例分享 如何保障网络安全

网络发展是非常迅速的&#xff0c;互联网在给人们带来生活娱乐便利的同时&#xff0c;也带来了一些安全隐患&#xff0c;这就需要大家做好防骗规范&#xff0c;确保网络安全&#xff0c;51CTO学堂为大家分享下有关网络安全的案例&#xff0c;以供各位参考。 非法获取公民个人信…

2025新鲜出炉--前端面试题(一)

文章目录 1. vue3有用过吗, 和vue2之间有哪些区别2. vue-router有几种路由, 分别怎么实现3. webpack和rollup这两个什么区别, 你会怎么选择4. 你能简单介绍一下webpack项目的构建流程吗5. webpack平时有手写过loader和plugin吗6. webpack这块你平时做过哪些优化吗&#xff1f;7…

变化检测论文阅读合集

1. ChangeCLIP: Remote sensing change detection with multimodal vision-language representation learning 作者&#xff1a;Sijun Dong a, Libo Wang b, Bo Du c, Xiaoliang Meng a,* 年份&#xff1a;2024 研究方法/模型&#xff1a; 重构原始CLIP&#xff1a;提取双时…

viem库

viem是一个用于和以太坊进行交互的javascript库&#xff0c;它提供了简单的API进行智能合约的读取和写入操作&#xff0c;你可以使用它来与区块链上智能合约进行交互&#xff0c;查询链上数据等。 基本功能 1&#xff0c;创建公有客户端 createPublicClient 可以创建一个链接…

2025影视泛目录站群程序设计_源码二次开发新版本无缓存刷新不变实现原理

1. 引言 本设站群程序计书旨在详细阐述苹果CMS泛目录的创新设计与实现&#xff0c;介绍无缓存刷新技术、数据统一化、局部URL控制及性能优化等核心功能&#xff0c;以提升网站访问速度和用户体验。 2. 技术概述 2.1 无缓存刷新技术 功能特点&#xff1a; 内容不变性&#x…

OpenEuler学习笔记(二十三):在OpenEuler上部署开源MES系统

在OpenEuler上部署小企业开源MES&#xff08;制造执行系统&#xff0c;Manufacturing Execution System&#xff09;是一个非常有价值的项目&#xff0c;可以帮助企业实现生产过程的数字化管理。以下是基于开源MES系统&#xff08;如 Odoo MES 或 OpenMES&#xff09;的部署步骤…

大数据项目2:基于hadoop的电影推荐和分析系统设计和实现

前言 大数据项目源码资料说明&#xff1a; 大数据项目资料来自我多年工作中的开发积累与沉淀。 我分享的每个项目都有完整代码、数据、文档、效果图、部署文档及讲解视频。 可用于毕设、课设、学习、工作或者二次开发等&#xff0c;极大提升效率&#xff01; 1、项目目标 本…

c++ haru生成pdf输出饼图

#define PI 3.14159265358979323846 // 绘制饼图的函数 void draw_pie_chart(HPDF_Doc pdf, HPDF_Page page, float *data, int data_count, float x, float y, float radius) { float total 0; int i; // 计算数据总和 for (i 0; i < data_count; i) { tot…

STM32 Unix时间戳

Unix时间戳 Unix 时间戳&#xff08;Unix Timestamp&#xff09;定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数&#xff0c;不考虑闰秒 时间戳存储在一个秒计数器中&#xff0c;秒计数器为32位/64位的整型变量 世界上所有时区的秒计数器相同&#xff0c;不同时区通过…

Spring Boot启动内嵌tocmat原理

要研究Spring Boot启动内嵌tomcat的原理&#xff0c;就需要先了解一下Spring Boot自动配置的过程&#xff0c;首先简要的梳理一下springboot自动配置的步骤。 一、SpringBoot自动配置 当SpringBoot应用启动时&#xff0c;EnableAutoConfiguration注解被激活&#xff0c;该注解…

腾讯云AI代码助手评测:如何智能高效完成Go语言Web项目开发

腾讯云AI代码助手评测&#xff1a;如何智能高效完成Go语言Web项目开发 ?? 文章目录 腾讯云AI代码助手评测&#xff1a;如何智能高效完成Go语言Web项目开发 ?? 背景引言开发环境介绍腾讯云AI代码助手使用实例 1. 代码补全2. 技术对话3. 代码优化4. 规范代码5. Bug处理 获得…

feign 远程调用详解

在平常的开发工作中&#xff0c;我们经常需要跟其他系统交互&#xff0c;比如调用用户系统的用户信息接口、调用支付系统的支付接口等。那么&#xff0c;我们应该通过什么方式进行系统之间的交互呢&#xff1f;今天&#xff0c;简单来总结下 feign 的用法。 1&#xff1a;引入依…

【JVM详解三】垃圾回收机制

一、对象是否存活 强引用&#xff1a;Object obj new Object(); 只要强引用还在&#xff0c;垃圾收集器永远不会回收掉被引用的对象。在不用对象的时将引用赋值为 null&#xff0c;能够帮助垃圾回收器回收对象。比如 ArrayList 的 clear() 方法实现。软引用&#xff08;SoftRe…

基于lstm+gru+transformer的电池寿命预测健康状态预测-完整数据代码

项目视频讲解: 毕业设计:基于lstm+gru+transformer的电池寿命预测 健康状态预测_哔哩哔哩_bilibili 数据: 实验结果:

opentelemetry-collector 配置elasticsearch

一、修改otelcol-config.yaml receivers:otlp:protocols:grpc:endpoint: 0.0.0.0:4317http:endpoint: 0.0.0.0:4318 exporters:debug:verbosity: detailedotlp/jaeger: # Jaeger supports OTLP directlyendpoint: 192.168.31.161:4317tls:insecure: trueotlphttp/prometheus: …

uniapp访问django目录中的图片和视频,2025[最新]中间件访问方式

新建中间件, middleware.py 匹配,以/cover_image/ 开头的图片 匹配以/episode_video/ 开头的视频 imageSrc: http://192.168.110.148:8000/cover_image/12345/1738760890657_mmexport1738154397386.jpg, videoSrc: http://192.168.110.148:8000/episode_video/12345/compres…

ChunkKV:优化 KV 缓存压缩,让 LLM 长文本推理更高效

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…