首页 > 其他分享 >Frpc 内网穿透客户端配置教程

Frpc 内网穿透客户端配置教程

时间:2024-08-01 17:28:51浏览次数:6  
标签:教程 FrpcIniConst string filePath App Frpc writeFrpcIni public 客户端

github: https://github.com/fatedier/frp/releases
1 下载操作系统对应版本的Frpc.exe 客户端程序
2 配置对应的frpc.ini文件
3 切换到Frpc.exe目录,cmd执行:Frpc.exe -c frpc.ini

 例如:frpc.ini 如下

例如  frps服务地址:10.10.10.10  端口10000

本地服务端口5000,  frps 域名219801a6865241m00017testappe.frp.ws.com,端口8000

本地应用唯一实例:[219801a6865241m00017testapp]

 假设本地Api为:http://192.169.137.10/5000/edit;postId=18337057#postBody

内网穿透代理为:http://219801a6865241m00017testappe.frp.ws.com/8000/edit;postId=18337057#postBody

注意:frpc.ini 配置通过请求后台下发

 /// <summary>
 /// 内网穿透代理客户端配置
 /// </summary>
 public class FrpcIni
 {
     public CommonSection Common { get; set; }
     public AppSection App { get; set; }
 }

 /// <summary>
 /// 公共配置节点
 /// </summary>
 public class CommonSection
 {
     public string ServerAddress { get; set; }
     public string ServerPort { get; set; }
     public string AuthenticationMethod { get; set; }
     public string Token { get; set; }
     public string DialServerTimeout { get; set; }
     public string LoginFailExit { get; set; }
 }

 /// <summary>
 /// 应用配置
 /// </summary>
 public class AppSection
 {
     public string Type { get; set; }
     public string RemotePort { get; set; }
     public string LocalIp { get; set; }
     public string LocalPort { get; set; }
     public string UseCompression { get; set; }
     public string CustomDomains { get; set; }
 }

 

    /// <summary>
    /// 代理客户端Ini配置常量
    /// </summary>
    internal class FrpcIniConst
    {
        //与服务端连接段和Key
        public const string CommonSection = "common";
        public const string ServerAddrKey = "server_addr";
        public const string ServerPortKey = "server_port";
        public const string AuthenticationMethodKey = "authentication_method";
        public const string TokenKey = "token";
        public const string DialServerTimeout = "dial_server_timeout";
        public const string LoginFailExit = "login_fail_exit";

        //单应用段和Key
        public const string AppSection = "app_name";
        public const string TypeKey = "type";
        public const string LocalIpKey = "local_ip";
        public const string LocalPortKey = "local_port";
        public const string UseCompressionKey = "use_compression";
        public const string CustomDomainsKey = "custom_domains";
        public const string RemotePortKey = "remote_port";

        public const string FrpcName = "frpc";
    }

  

/// <summary>
/// 代理配置操作
/// </summary>
internal class FrpcConfigurationOperation
{
    /// <summary>
    /// 配置操作
    /// </summary>
    /// <param name="responseRegister">注册响应的包</param>
    /// <param name="localServicePort">本地服务端口号</param>
    /// <param name="appSection">应用节点</param>
    public FrpcConfigurationOperation(ResponseRegister responseRegister, int localServicePort, string appSection)
    {
        _responseRegister = responseRegister;
        _localServicePort = localServicePort;
        _appSection = appSection;
    }

    /// <summary>
    /// 更新配置
    /// </summary>
    /// <param name="frpcIniPath"></param>
    public void UpDateFrpcIni( string frpcIniPath)
    {
        var writeFrpcIni = ResponseToFrpcIni(_responseRegister, _localServicePort, _appSection);
        var readFrpcIni = ReadFrpcIniFromFile(frpcIniPath, _appSection);
        WriteFrpcIniToFile(frpcIniPath, writeFrpcIni, readFrpcIni, _appSection);
    }

    /// <summary>
    /// 响应包转换配置
    /// </summary>
    /// <returns></returns>
    public FrpcIni ResponseToFrpcIni()
    {
        return ResponseToFrpcIni(_responseRegister, _localServicePort, _appSection);
    }

    /// <summary>
    /// 响应包转换配置
    /// </summary>
    /// <param name="responseRegister"></param>
    /// <param name="localServicePort"></param>
    /// <param name="appSection"></param>
    /// <returns></returns>
    private FrpcIni ResponseToFrpcIni(ResponseRegister responseRegister, int localServicePort, string appSection)
    {
        if (responseRegister.Server == null) throw new InvalidOperationException("无法获取服务信息");
        if (!responseRegister.SubDomainList.Any()) throw new InvalidOperationException("无法获取分配的子域");
        var app = responseRegister.SubDomainList.First(s => s.Subdomain.StartsWith(appSection, StringComparison.CurrentCultureIgnoreCase));

        if (app == null) throw new InvalidOperationException("无法获取分配的子域");

        var frpcIni = new FrpcIni
        {
            Common = new CommonSection
            {
                ServerAddress = responseRegister.Server.ServerAddress,
                ServerPort = responseRegister.Server.ServerPort,
                AuthenticationMethod = responseRegister.Server.AuthenticationMethod,
                Token = responseRegister.Server.Token,
                DialServerTimeout = responseRegister.Server.DialServerTimeout,
                LoginFailExit = responseRegister.Server.LoginFailExit,
            },
            App = new AppSection()
        };
        frpcIni.App.Type = app.Type;
        frpcIni.App.RemotePort = app.RemotePort;
        frpcIni.App.UseCompression = app.UseCompression;

        //必须小写,否则路由无法找到:frp已知问题
        frpcIni.App.CustomDomains = app.CustomDomain;
        frpcIni.App.LocalIp = LocalIp;
        frpcIni.App.LocalPort = localServicePort.ToString();
        return frpcIni;
    }

    /// <summary>
    /// 从文件读取代理客户端配置
    /// </summary>
    /// <param name="filePath"></param>
    /// <param name="appSection"></param>
    /// <returns></returns>
    private FrpcIni ReadFrpcIniFromFile(string filePath, string appSection)
    {
        if (!File.Exists(filePath)) return null;
        DeleteErrorSection(filePath, appSection);

        return new FrpcIni
        {
            Common = new CommonSection
            {
                ServerAddress = IniHelper.Read(filePath, FrpcIniConst.CommonSection, FrpcIniConst.ServerAddrKey),
                ServerPort = IniHelper.Read(filePath, FrpcIniConst.CommonSection, FrpcIniConst.ServerPortKey),
                AuthenticationMethod = IniHelper.Read(filePath, FrpcIniConst.CommonSection, FrpcIniConst.AuthenticationMethodKey),
                Token = IniHelper.Read(filePath, FrpcIniConst.CommonSection, FrpcIniConst.TokenKey),
                DialServerTimeout = IniHelper.Read(filePath, FrpcIniConst.CommonSection, FrpcIniConst.DialServerTimeout),
                LoginFailExit = IniHelper.Read(filePath, FrpcIniConst.CommonSection, FrpcIniConst.LoginFailExit)
            },
            App = new AppSection
            {
                Type = IniHelper.Read(filePath, appSection, FrpcIniConst.TypeKey),
                LocalIp = IniHelper.Read(filePath, appSection, FrpcIniConst.LocalIpKey),
                LocalPort = IniHelper.Read(filePath, appSection, FrpcIniConst.LocalPortKey),
                UseCompression = IniHelper.Read(filePath, appSection, FrpcIniConst.UseCompressionKey),
                CustomDomains = IniHelper.Read(filePath, appSection, FrpcIniConst.CustomDomainsKey),
                RemotePort = IniHelper.Read(filePath, appSection, FrpcIniConst.RemotePortKey)
            }
        };
    }

    /// <summary>
    /// 向文件写入代理客户端配置
    /// </summary>
    /// <param name="filePath"></param>
    /// <param name="writeFrpcIni"></param>
    /// <param name="readFrpcIni"></param>
    /// <param name="appSection"></param>
    private void WriteFrpcIniToFile(string filePath, FrpcIni writeFrpcIni, FrpcIni readFrpcIni, string appSection)
    {
        if (IsNeedWrite(writeFrpcIni.Common.ServerAddress, readFrpcIni.Common.ServerAddress))
            IniHelper.Write(filePath, FrpcIniConst.CommonSection, FrpcIniConst.ServerAddrKey, writeFrpcIni.Common.ServerAddress);

        if (IsNeedWrite(writeFrpcIni.Common.ServerPort, readFrpcIni.Common.ServerPort))
            IniHelper.Write(filePath, FrpcIniConst.CommonSection, FrpcIniConst.ServerPortKey, writeFrpcIni.Common.ServerPort);

        if (IsNeedWrite(writeFrpcIni.Common.AuthenticationMethod, readFrpcIni.Common.AuthenticationMethod))
            IniHelper.Write(filePath, FrpcIniConst.CommonSection, FrpcIniConst.AuthenticationMethodKey, writeFrpcIni.Common.AuthenticationMethod);

        if (IsNeedWrite(writeFrpcIni.Common.Token, readFrpcIni.Common.Token))
            IniHelper.Write(filePath, FrpcIniConst.CommonSection, FrpcIniConst.TokenKey, writeFrpcIni.Common.Token);

        if (IsNeedWrite(writeFrpcIni.Common.DialServerTimeout, readFrpcIni.Common.DialServerTimeout))
            IniHelper.Write(filePath, FrpcIniConst.CommonSection, FrpcIniConst.DialServerTimeout, writeFrpcIni.Common.DialServerTimeout);

        if (IsNeedWrite(writeFrpcIni.Common.LoginFailExit, readFrpcIni.Common.LoginFailExit))
            IniHelper.Write(filePath, FrpcIniConst.CommonSection, FrpcIniConst.LoginFailExit, writeFrpcIni.Common.LoginFailExit);

        if (IsNeedWrite(writeFrpcIni.App.Type, readFrpcIni.App.Type))
            IniHelper.Write(filePath, appSection, FrpcIniConst.TypeKey, writeFrpcIni.App.Type);

        if (IsNeedWrite(writeFrpcIni.App.LocalIp, readFrpcIni.App.LocalIp))
            IniHelper.Write(filePath, appSection, FrpcIniConst.LocalIpKey, writeFrpcIni.App.LocalIp);

        if (IsNeedWrite(writeFrpcIni.App.LocalPort, readFrpcIni.App.LocalPort))
            IniHelper.Write(filePath, appSection, FrpcIniConst.LocalPortKey, writeFrpcIni.App.LocalPort);

        if (IsNeedWrite(writeFrpcIni.App.UseCompression, readFrpcIni.App.UseCompression))
            IniHelper.Write(filePath, appSection, FrpcIniConst.UseCompressionKey, writeFrpcIni.App.UseCompression);

        if (IsNeedWrite(writeFrpcIni.App.CustomDomains, readFrpcIni.App.CustomDomains, false))
            IniHelper.Write(filePath, appSection, FrpcIniConst.CustomDomainsKey, writeFrpcIni.App.CustomDomains);

        if (IsNeedWrite(writeFrpcIni.App.RemotePort, readFrpcIni.App.RemotePort, false))
            IniHelper.Write(filePath, appSection, FrpcIniConst.RemotePortKey, writeFrpcIni.App.RemotePort);
    }

    /// <summary>
    /// 需要写入
    /// </summary>
    /// <param name="writeValue"></param>
    /// <param name="readValue"></param>
    /// <param name="ignoreCase"></param>
    /// <returns></returns>
    private bool IsNeedWrite(string writeValue, string readValue, bool ignoreCase = true)
    {
        if (string.IsNullOrWhiteSpace(writeValue)) return true;

        if (ignoreCase)
            return !writeValue.Equals(readValue, StringComparison.CurrentCultureIgnoreCase);

        return !writeValue.Equals(readValue);
    }

    /// <summary>
    /// 删除错误节点
    /// </summary>
    /// <param name="filePath"></param>
    /// <param name="appSection"></param>
    private void DeleteErrorSection(string filePath, string appSection)
    {
        var sections = IniHelper.ReadSections(filePath);
        if (sections == null || sections.Count <= 0) return;
        var ignoreSection = FrpcIniConst.CommonSection;
        foreach (var section in sections)
        {
            if (section.Equals(ignoreSection) || section.Equals(appSection))
                continue;
            IniHelper.DeleteSection(filePath, section);
        }
    }

    private const string LocalIp = "localhost";
    private readonly ResponseRegister _responseRegister;
    private readonly int _localServicePort;
    private readonly string _appSection;
}

  

  /// <summary>
  /// 代理状态
  /// </summary>
  public enum FrpcAgentStatus
  {
      [Description("未知状态")]
      UnKnow = -1,

      [Description("代理开启成功")]
      StartUpSuccess =0,

      [Description("代理开启失败")]
      StartUpFailed = 1,

      [Description("代理关闭")]
      Closed = 2,

      [Description("代理路由冲突")]
      Conflict = 3,

      [Description("代理被拒绝连接")]
      Refused =4,
  }

  

/// <summary>
/// 代理内网穿透客户端
/// </summary>
public class FrpcAgent
{
    /// <summary>
    /// 连接改变
    /// </summary>
    public event EventHandler<bool> ConnectedChanged;
    /// <summary>
    /// 代理接收信息
    /// </summary>
    public event EventHandler<string> OutputReceived;
    /// <summary>
    /// 代理收错误信息
    /// </summary>
    public event EventHandler<string> ErrorReceived;
    /// <summary>
    /// 代理状态
    /// </summary>
    public event EventHandler<FrpcAgentStatus> AgentStatus;

    public FrpcAgent()
    {
        Application.Current.Dispatcher?.Invoke(() =>
        {
            Application.Current.Exit += Current_Exit;
        });
    }

    /// <summary>
    /// 退出代理
    /// </summary>
    public void Exit()
    {
        Application.Current.Dispatcher?.Invoke(() =>
        {
            Application.Current.Exit -= Current_Exit;
        });
        Current_Exit(null, null);
    }

    /// <summary>
    /// 开启代理
    /// </summary>
    /// <returns></returns>
    public async Task Start(string intranetPenetrationPath)
    {
        await Task.Run(() =>
        {
            _frpcAgentFullName = Path.Combine(intranetPenetrationPath, $"{FrpcIniConst.FrpcName}.exe");
            KillLocalMainModule(_frpcAgentFullName);
            StartProcess(_frpcAgentFullName, AgentIniParameter(), intranetPenetrationPath);
        });
    }

    #region 私有方法
    private void StartProcess(string projectUrl, string arguments, string intranetPenetrationPath)
    {
        ExitedHandle();
        
        _frpcProcess = new Process
        {
            StartInfo =
            {
                UseShellExecute = false,
                WorkingDirectory=intranetPenetrationPath,
                FileName = projectUrl,
                Arguments = arguments,
                CreateNoWindow = true,
                WindowStyle = ProcessWindowStyle.Hidden
            },
            EnableRaisingEvents = true
        };

        //守护重启
        _frpcProcess.Exited += FrpcProcess_Exited;
        _frpcProcess.StartInfo.RedirectStandardInput = true;
        _frpcProcess.StartInfo.RedirectStandardOutput = true;
        _frpcProcess.StartInfo.RedirectStandardError = true;
        _frpcProcess.StartInfo.StandardErrorEncoding = Encoding.UTF8;
        _frpcProcess.StartInfo.StandardOutputEncoding = Encoding.UTF8;

        _frpcProcess.OutputDataReceived += FrpcProcess_OutputDataReceived;
        _frpcProcess.ErrorDataReceived += FrpcProcess_ErrorDataReceived;
        _frpcProcess.Start();
        _frpcProcess.BeginOutputReadLine();
        _frpcProcess.BeginErrorReadLine();
    }

    private void FrpcProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        if (!string.IsNullOrWhiteSpace(e.Data))
            ErrorReceived?.Invoke(sender, $"{FrpcIniConst.FrpcName} -ErrorDataReceived: {e.Data}");
    }

    private void FrpcProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        var strOutput = e.Data;
        if (string.IsNullOrWhiteSpace(strOutput)) return;
        var agentStatus = GetAgentStatus(strOutput);
        switch (agentStatus)
        {
            case FrpcAgentStatus.StartUpSuccess:
                ConnectedChanged?.Invoke(this, true);
                break;
            case FrpcAgentStatus.StartUpFailed:
                ConnectedChanged?.Invoke(this, false);
                break;
            case FrpcAgentStatus.Closed:
                ConnectedChanged?.Invoke(this, false);
                break;
            case FrpcAgentStatus.Conflict:
                ConnectedChanged?.Invoke(this, false);
                KillLocalMainModule(_frpcAgentFullName);
                AgentStatus?.Invoke(sender, FrpcAgentStatus.Conflict);
                break;
            case FrpcAgentStatus.Refused:
                ConnectedChanged?.Invoke(this, false);
                Exit();
                AgentStatus?.Invoke(sender, FrpcAgentStatus.Refused);
                break;
            case FrpcAgentStatus.UnKnow:
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
        OutputReceived?.Invoke(sender, $"{FrpcIniConst.FrpcName} -OutputDataReceived: {strOutput}");
    }

    private void FrpcProcess_Exited(object sender, EventArgs e)
    {
        ExitedHandle();
    }

    private void ExitedHandle()
    {
        if (_frpcProcess == null) return;
        
        _frpcProcess.Exited -= FrpcProcess_Exited;
        ConnectedChanged?.Invoke(this, false);
        OutputReceived?.Invoke(this, $"{FrpcIniConst.FrpcName} -Exited:");
        _frpcProcess.Dispose();
        _frpcProcess = null;
    }

    /// <summary>
    /// 返回代理状态
    /// </summary>
    /// <param name="strOutput"></param>
    /// <returns></returns>
    private FrpcAgentStatus GetAgentStatus(string strOutput)
    {
        var success = strOutput.ToLower().Contains(Proxy) && strOutput.ToLower().Contains(ProxySuccess);
        if (success) return FrpcAgentStatus.StartUpSuccess;

        var error = strOutput.ToLower().Contains(Proxy) && strOutput.ToLower().Contains(ProxyError);
        if (error) return FrpcAgentStatus.StartUpFailed;

        var close = strOutput.ToLower().Contains(Closing) || strOutput.ToLower().Contains(Closed) || strOutput.ToLower().Contains(Failed);
        if (close) return FrpcAgentStatus.Closed;

        var conflict = strOutput.ToLower().Contains(Conflict);
        if (conflict) return FrpcAgentStatus.Conflict;

        var refused = strOutput.ToLower().Contains(Refused);
        if (refused) return FrpcAgentStatus.Refused;
        return FrpcAgentStatus.UnKnow;
    }

    /// <summary>
    /// 杀掉当前应用域下的代理客户端
    /// </summary>
    private void KillLocalMainModule(string agentFullName)
    {
        Process[] services = null;
        try
        {
            services = Process.GetProcessesByName(FrpcIniConst.FrpcName);
            if (services.Length <= 0) return;
            foreach (var service in services)
            {
                if (service.MainModule != null &&
                    service.MainModule.FileName.StartsWith(agentFullName,
                        StringComparison.CurrentCultureIgnoreCase))
                    service.Kill();
            }
        }
        catch (Exception e)
        {
            ErrorReceived?.Invoke(null, e.Message);
        }
        finally
        {
            if (services != null)
            {
                foreach (var process in services)
                {
                    process.Dispose();
                }
            }
        }
    }

    private void Current_Exit(object sender, ExitEventArgs e)
    {
        try
        {
            if (_frpcProcess != null)
            {
                _frpcProcess.Exited -= FrpcProcess_Exited;
                _frpcProcess.OutputDataReceived -= FrpcProcess_OutputDataReceived;
                _frpcProcess.ErrorDataReceived -= FrpcProcess_ErrorDataReceived;
            }

            _frpcProcess?.Kill();
            _frpcProcess?.Close();
            _frpcProcess?.Dispose();
            _frpcProcess = null;
        }
        catch (Exception ex)
        {
            ErrorReceived?.Invoke(null, ex.Message);
        }
    }

    /// <summary>
    /// 代理配置
    /// </summary> 
    private string AgentIniParameter() => $"-c {FrpcIniConst.FrpcName}.ini";
    #endregion

    #region 私有字段
    //代理开启成功
    private const string Proxy = "proxy";
    private const string ProxySuccess = "success";

    //代理开启失败
    private const string ProxyError = "error";
    private const string Failed = "failed";

    //断开
    private const string Closing = "closing";
    private const string Closed = "closed";

    //冲突
    private const string Conflict = "conflict";
    private const string Refused = "refused";

    //代理客户端完整路径
    private string _frpcAgentFullName;
    private Process _frpcProcess;
    #endregion
}

  

 

 

标签:教程,FrpcIniConst,string,filePath,App,Frpc,writeFrpcIni,public,客户端
From: https://www.cnblogs.com/terryK/p/18337057

相关文章

  • 加工策略丰富的数控加工编程软件PowerMill 2025 软件安装教程
    PowerMILL是一款加工策略丰富的数控加工编程软件系统,采用全新的中文WINDOWS用户界面,提供完善的加工策略。帮助用户产生最佳的加工方案,从而提高加工效率,减少手工修整,快速产生粗、精加工路径,具有集成的加工实体仿真,方便用户在加工前了解整个加工过程及加工结果。软件安装1、双击......
  • 大型IM稳定性监测实践:手Q客户端性能防劣化系统的建设之路
    本文来自腾讯手Q基础架构团队杨萧玉、邱少雄、张自蹊、王褚重天、姚伟斌的分享,原题“QQ客户端性能稳定性防劣化系统Hodor技术方案”,下文进行了排版和内容优化。1、引言接上篇《首次公开,最新手机QQ客户端架构的技术演进实践》。防劣化是比较经典的技术话题,手Q的防劣化系......
  • 体验教程:通义灵码陪你备战求职季
    本场景将带大家体验在技术面试准备场景下,如何通过使用阿里云通义灵码实现高效的编程算法题练习、代码优化、技术知识查询等工作,帮助开发者提升实战能力,更加从容地应对面试挑战。主要包括:1、模拟题练习:精心挑选百道阿里巴巴历史校招技术面试/笔试题,帮助开发者更加准确地了解程序......
  • 微信小程序教程010:列表渲染
    文章目录列表渲染1、wx:for2、手动指定索引和当前项的变量名3、wx:key的使用列表渲染1、wx:for通过wx:for可以根据指定的数组,循环渲染重复的组件结构,语法结构如下:<viewwx:for="{{array}}"> 索引是:{{index}},当前项是:{{item}}</view>定义数......
  • 抖音私信如何跳转微信,抖音卡片制作教程
       在社交媒体平台中,抖音和微信都是非常受欢迎的应用程序。抖音是一款短视频分享平台,而微信是一款社交聊天应用。有时候,我们可能希望将抖音视频分享到微信上,但是却无法直接在抖音上找到跳转微信的功能。所以在本文中,我们将探讨如何生成抖音跳转微信链接的方法。首先,我们需要......
  • 体验教程:通义灵码陪你备战求职季
    本场景将带大家体验在技术面试准备场景下,如何通过使用阿里云通义灵码实现高效的编程算法题练习、代码优化、技术知识查询等工作,帮助开发者提升实战能力,更加从容地应对面试挑战。主要包括:1、模拟题练习:精心挑选百道阿里巴巴历史校招技术面试/笔试题,帮助开发者更加准确地了解程序......
  • 初学者友好!从零到一快速上手PyCharm安装的超详细图解+避坑指南教程
    一,pycharm的官网下载下载地址:www.jetbrains.com/pycharm/本文将从Python解释器安装到Pycharm专业版安装和配置汉化等使用都进行了详细介绍,希望能够帮助到大家。Python解释器&Pycharm安装包&Pycharm破姐插件我都打包好了。 ......
  • 计算机基础(Windows 10+Office 2016)教程 —— 第5章 文档编辑软件Word 2016(上)
    文档编辑软件Word20165.1Word2016入门5.1.1Word2016简介5.1.2Word2016的启动5.1.3Word2016的窗口组成5.1.4Word2016的视图方式5.1.5Word2016的文档操作5.1.6Word2016的退出5.2Word2016的文本编辑5.2.1输入文本5.2.3插入与删除文本5.2.4复制与......
  • 遥感数据与作物生长模型同化及在作物长势监测与估产技术教程
    原文链接:遥感数据与作物生长模型同化及在作物长势监测与估产技术教程https://mp.weixin.qq.com/s?__biz=MzUzNTczMDMxMg==&mid=2247610916&idx=6&sn=450eff7ab4f0d4f31d1f61bd751297b0&chksm=fa8273c3cdf5fad5f40311549fef1d6fa16547ca6cb4e2eddd79b2d10dc2812982b90c0dcdff&to......
  • zabbix应用教程:基于Nginx页面响应的日志监控用例
    作者乐维社区(forum.lwops.cn)许远背景:某公司基于Nginx服务器搭建的网站,需要监控页面响应耗时的数据,因此该公司搭建了zabbix开源监控系统,当监控到页面响应时间超过3000ms阈值时,就进行告警通知。本文将通过日志关键字的监控来实现对页面响应时间感知,示例Zabbix版本:5.0.9。日志文......