您当前的位置:首页 > 电脑百科 > 站长技术 > 服务器

Nginx 模块的基本结构

时间:2019-11-26 13:40:01  来源:  作者:
Nginx 模块的基本结构

 

模块配置结构

基本上每个模块都会提供一些配置指令,以便于用户可以通过配置来控制该模块的行为。那么这些配置信息怎么存储呢?那就需要定义该模块的配置结构来进行存储。

大家都知道 Nginx 的配置信息分成了几个作用域(scope,有时也称作上下文),这就是 main,server 以及 location。同样的每个模块提供的配置指令也可以出现在这几个作用域里。那对于这三个作用域的配置信息,每个模块就需要定义三个不同的数据结构去进行存储。当然,不是每个模块都会在这三个作用域都提供配置指令的。那么也就不一定每个模块都需要定义三个数据结构去存储这些配置信息了。视模块的实现而言,需要几个就定义几个。

有一点需要特别注意的就是,在模块的开发过程中,我们最好使用 Nginx 原有的命名习惯。这样跟原代码的契合度更高,看起来也更舒服。

对于模块配置信息的定义,命名习惯是ngx_http_<module name>_(main|srv|loc)_conf_t。这里有个例子,就是从我们后面将要展示给大家的 hello module 中截取的。

 typedef struct
 {
 ngx_str_t hello_string;
 ngx_int_t hello_counter;
 }ngx_http_hello_loc_conf_t;

模块配置指令

一个模块的配置指令是定义在一个静态数组中的。同样地,我们来看一下从 hello module 中截取的模块配置指令的定义。

 static ngx_command_t ngx_http_hello_commands[] = {
 { 
 ngx_string("hello_string"),
 NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
 ngx_http_hello_string,
 NGX_HTTP_LOC_CONF_OFFSET,
 offsetof(ngx_http_hello_loc_conf_t, hello_string),
 NULL },
 { 
 ngx_string("hello_counter"),
 NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
 ngx_http_hello_counter,
 NGX_HTTP_LOC_CONF_OFFSET,
 offsetof(ngx_http_hello_loc_conf_t, hello_counter),
 NULL }, 
 ngx_null_command
 };

其实看这个定义,就基本能看出来一些信息。例如,我们是定义了两个配置指令,一个是叫 hello_string,可以接受一个参数,或者是没有参数。另外一个命令是 hello_counter,接受一个 NGX_CONF_FLAG 类型的参数。除此之外,似乎看起来有点迷惑。没有关系,我们来详细看一下 ngx_command_t,一旦我们了解这个结构的详细信息,那么我相信上述这个定义所表达的所有信息就不言自明了。

ngx_command_t 的定义,位于src/core/ngx_conf_file.h中。

 struct ngx_command_s {
 ngx_str_t name;
 ngx_uint_t type;
 char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 ngx_uint_t conf;
 ngx_uint_t offset;
 void *post;
 };

name: 配置指令的名称。

type: 该配置的类型,其实更准确一点说,是该配置指令属性的集合。Nginx 提供了很多预定义的属性值(一些宏定义),通过逻辑或运算符可组合在一起,形成对这个配置指令的详细的说明。下面列出可在这里使用的预定义属性值及说明。

  • NGX_CONF_NOARGS:配置指令不接受任何参数。
  • NGX_CONF_TAKE1:配置指令接受 1 个参数。
  • NGX_CONF_TAKE2:配置指令接受 2 个参数。
  • NGX_CONF_TAKE3:配置指令接受 3 个参数。
  • NGX_CONF_TAKE4:配置指令接受 4 个参数。
  • NGX_CONF_TAKE5:配置指令接受 5 个参数。
  • NGX_CONF_TAKE6:配置指令接受 6 个参数。
  • NGX_CONF_TAKE7:配置指令接受 7 个参数。

可以组合多个属性,比如一个指令即可以不填参数,也可以接受1个或者2个参数。那么就是NGX_CONF_NOARGS|NGX_CONF_TAKE1|NGX_CONF_TAKE2。如果写上面三个属性在一起,你觉得麻烦,那么没有关系,Nginx 提供了一些定义,使用起来更简洁。

  • NGX_CONF_TAKE12:配置指令接受 1 个或者 2 个参数。
  • NGX_CONF_TAKE13:配置指令接受 1 个或者 3 个参数。
  • NGX_CONF_TAKE23:配置指令接受 2 个或者 3 个参数。
  • NGX_CONF_TAKE123:配置指令接受 1 个或者 2 个或者 3 参数。
  • NGX_CONF_TAKE1234:配置指令接受 1 个或者 2 个或者 3 个或者 4 个参数。
  • NGX_CONF_1MORE:配置指令接受至少一个参数。
  • NGX_CONF_2MORE:配置指令接受至少两个参数。
  • NGX_CONF_MULTI: 配置指令可以接受多个参数,即个数不定。
  • NGX_CONF_BLOCK:配置指令可以接受的值是一个配置信息块。也就是一对大括号括起来的内容。里面可以再包括很多的配置指令。比如常见的 server 指令就是这个属性的。
  • NGX_CONF_FLAG:配置指令可以接受的值是"on"或者"off",最终会被转成 bool 值。
  • NGX_CONF_ANY:配置指令可以接受的任意的参数值。一个或者多个,或者"on"或者"off",或者是配置块。

最后要说明的是,无论如何,Nginx 的配置指令的参数个数不可以超过 NGX_CONF_MAX_ARGS 个。目前这个值被定义为 8,也就是不能超过 8 个参数值。

下面介绍一组说明配置指令可以出现的位置的属性。

  • NGX_DIRECT_CONF:可以出现在配置文件中最外层。例如已经提供的配置指令 daemon,master_process 等。
  • NGX_MAIN_CONF: http、mail、events、error_log 等。
  • NGX_ANY_CONF: 该配置指令可以出现在任意配置级别上。

对于我们编写的大多数模块而言,都是在处理http相关的事情,也就是所谓的都是NGX_HTTP_MODULE,对于这样类型的模块,其配置可能出现的位置也是分为直接出现在http里面,以及其他位置。

  • NGX_HTTP_MAIN_CONF: 可以直接出现在 http 配置指令里。
  • NGX_HTTP_SRV_CONF: 可以出现在 http 里面的 server 配置指令里。
  • NGX_HTTP_LOC_CONF: 可以出现在 http server 块里面的 location 配置指令里。
  • NGX_HTTP_UPS_CONF: 可以出现在 http 里面的 upstream 配置指令里。
  • NGX_HTTP_SIF_CONF: 可以出现在 http 里面的 server 配置指令里的 if 语句所在的 block 中。
  • NGX_HTTP_LMT_CONF: 可以出现在 http 里面的 limit_except 指令的 block 中。
  • NGX_HTTP_LIF_CONF: 可以出现在 http server 块里面的 location 配置指令里的 if 语句所在的 block 中。

set: 这是一个函数指针,当 Nginx 在解析配置的时候,如果遇到这个配置指令,将会把读取到的值传递给这个函数进行分解处理。因为具体每个配置指令的值如何处理,只有定义这个配置指令的人是最清楚的。来看一下这个函数指针要求的函数原型。

char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

先看该函数的返回值,处理成功时,返回 NGX_OK,否则返回 NGX_CONF_ERROR 或者是一个自定义的错误信息的字符串。

再看一下这个函数被调用的时候,传入的三个参数。

  • cf: 该参数里面保存从配置文件读取到的原始字符串以及相关的一些信息。特别注意的是这个参数的args字段是一个 ngx_str_t类型的数组,该数组的首个元素是这个配置指令本身,第二个元素是指令的第一个参数,第三个元素是第二个参数,依次类推。
  • cmd: 这个配置指令对应的 ngx_command_t 结构。
  • conf: 就是定义的存储这个配置值的结构体,比如在上面展示的那个 ngx_http_hello_loc_conf_t。当解析这个 hello_string 变量的时候,传入的 conf 就指向一个 ngx_http_hello_loc_conf_t 类型的变量。用户在处理的时候可以使用类型转换,转换成自己知道的类型,再进行字段的赋值。

为了更加方便的实现对配置指令参数的读取,Nginx 已经默认提供了对一些标准类型的参数进行读取的函数,可以直接赋值给 set 字段使用。下面来看一下这些已经实现的 set 类型函数。

  • ngx_conf_set_flag_slot: 读取 NGX_CONF_FLAG 类型的参数。
  • ngx_conf_set_str_slot:读取字符串类型的参数。
  • ngx_conf_set_str_array_slot: 读取字符串数组类型的参数。
  • ngx_conf_set_keyval_slot: 读取键值对类型的参数。
  • ngx_conf_set_num_slot: 读取整数类型(有符号整数 ngx_int_t)的参数。
  • ngx_conf_set_size_slot:读取 size_t 类型的参数,也就是无符号数。
  • ngx_conf_set_off_slot: 读取 off_t 类型的参数。
  • ngx_conf_set_msec_slot: 读取毫秒值类型的参数。
  • ngx_conf_set_sec_slot: 读取秒值类型的参数。
  • ngx_conf_set_bufs_slot: 读取的参数值是 2 个,一个是 buf 的个数,一个是 buf 的大小。例如: output_buffers 1 128k;
  • ngx_conf_set_enum_slot: 读取枚举类型的参数,将其转换成整数 ngx_uint_t 类型。
  • ngx_conf_set_bitmask_slot: 读取参数的值,并将这些参数的值以 bit 位的形式存储。例如:HttpDavModule 模块的 dav_methods 指令。

conf: 该字段被 NGX_HTTP_MODULE 类型模块所用 (我们编写的基本上都是 NGX_HTTP_MOUDLE,只有一些 Nginx 核心模块是非 NGX_HTTP_MODULE),该字段指定当前配置项存储的内存位置。实际上是使用哪个内存池的问题。因为 http 模块对所有 http 模块所要保存的配置信息,划分了 main, server 和 location 三个地方进行存储,每个地方都有一个内存池用来分配存储这些信息的内存。这里可能的值为 NGX_HTTP_MAIN_CONF_OFFSET、NGX_HTTP_SRV_CONF_OFFSET 或 NGX_HTTP_LOC_CONF_OFFSET。当然也可以直接置为 0,就是 NGX_HTTP_MAIN_CONF_OFFSET。

offset: 指定该配置项值的精确存放位置,一般指定为某一个结构体变量的字段偏移。因为对于配置信息的存储,一般我们都是定义个结构体来存储的。那么比如我们定义了一个结构体 A,该项配置的值需要存储到该结构体的 b 字段。那么在这里就可以填写为 offsetof(A, b)。对于有些配置项,它的值不需要保存或者是需要保存到更为复杂的结构中时,这里可以设置为 0。

post: 该字段存储一个指针。可以指向任何一个在读取配置过程中需要的数据,以便于进行配置读取的处理。大多数时候,都不需要,所以简单地设为 0 即可。

看到这里,应该就比较清楚了。ngx_http_hello_commands 这个数组每 5 个元素为一组,用来描述一个配置项的所有情况。那么如果有多个配置项,只要按照需要再增加 5 个对应的元素对新的配置项进行说明。

需要注意的是,就是在ngx_http_hello_commands这个数组定义的最后,都要加一个ngx_null_command作为结尾。

模块上下文结构

这是一个 ngx_http_module_t 类型的静态变量。这个变量实际上是提供一组回调函数指针,这些函数有在创建存储配置信息的对象的函数,也有在创建前和创建后会调用的函数。这些函数都将被 Nginx 在合适的时间进行调用。

 typedef struct {
 ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
 ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
 void *(*create_main_conf)(ngx_conf_t *cf);
 char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
 void *(*create_srv_conf)(ngx_conf_t *cf);
 char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
 void *(*create_loc_conf)(ngx_conf_t *cf);
 char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
 } ngx_http_module_t; 
  • preconfiguration: 在创建和读取该模块的配置信息之前被调用。
  • postconfiguration: 在创建和读取该模块的配置信息之后被调用。
  • create_main_conf: 调用该函数创建本模块位于 http block 的配置信息存储结构。该函数成功的时候,返回创建的配置对象。失败的话,返回 NULL。
  • init_main_conf: 调用该函数初始化本模块位于 http block 的配置信息存储结构。该函数成功的时候,返回 NGX_CONF_OK。失败的话,返回 NGX_CONF_ERROR 或错误字符串。
  • create_srv_conf: 调用该函数创建本模块位于 http server block 的配置信息存储结构,每个 server block 会创建一个。该函数成功的时候,返回创建的配置对象。失败的话,返回 NULL。
  • merge_srv_conf: 因为有些配置指令既可以出现在 http block,也可以出现在 http server block 中。那么遇到这种情况,每个 server 都会有自己存储结构来存储该 server 的配置,但是在这种情况下 http block 中的配置与 server block 中的配置信息发生冲突的时候,就需要调用此函数进行合并,该函数并非必须提供,当预计到绝对不会发生需要合并的情况的时候,就无需提供。当然为了安全起见还是建议提供。该函数执行成功的时候,返回 NGX_CONF_OK。失败的话,返回 NGX_CONF_ERROR 或错误字符串。
  • create_loc_conf: 调用该函数创建本模块位于 location block 的配置信息存储结构。每个在配置中指明的 location 创建一个。该函数执行成功,返回创建的配置对象。失败的话,返回 NULL。
  • merge_loc_conf: 与 merge_srv_conf 类似,这个也是进行配置值合并的地方。该函数成功的时候,返回 NGX_CONF_OK。失败的话,返回 NGX_CONF_ERROR 或错误字符串。

Nginx 里面的配置信息都是上下一层层的嵌套的,对于具体某个 location 的话,对于同一个配置,如果当前层次没有定义,那么就使用上层的配置,否则使用当前层次的配置。

这些配置信息一般默认都应该设为一个未初始化的值,针对这个需求,Nginx 定义了一系列的宏定义来代表各种配置所对应数据类型的未初始化值,如下:

 #define NGX_CONF_UNSET -1
 #define NGX_CONF_UNSET_UINT (ngx_uint_t) -1
 #define NGX_CONF_UNSET_PTR (void *) -1
 #define NGX_CONF_UNSET_SIZE (size_t) -1
 #define NGX_CONF_UNSET_MSEC (ngx_msec_t) -1

又因为对于配置项的合并,逻辑都类似,也就是前面已经说过的,如果在本层次已经配置了,也就是配置项的值已经被读取进来了(那么这些配置项的值就不会等于上面已经定义的那些 UNSET 的值),就使用本层次的值作为定义合并的结果,否则,使用上层的值,如果上层的值也是这些UNSET类的值,那就赋值为默认值,否则就使用上层的值作为合并的结果。对于这样类似的操作,Nginx 定义了一些宏操作来做这些事情,我们来看其中一个的定义。

 #define ngx_conf_merge_uint_value(conf, prev, default) 
 if (conf == NGX_CONF_UNSET_UINT) { 
 conf = (prev == NGX_CONF_UNSET_UINT) ? default : prev; 
 }

显而易见,这个逻辑确实比较简单,所以其它的宏定义也类似,我们就列具其中的一部分吧。

 ngx_conf_merge_value
 ngx_conf_merge_ptr_value
 ngx_conf_merge_uint_value
 ngx_conf_merge_msec_value
 ngx_conf_merge_sec_value

等等。

下面来看一下 hello 模块的模块上下文的定义,加深一下印象。

 static ngx_http_module_t ngx_http_hello_module_ctx = {
 NULL, /* preconfiguration */
 ngx_http_hello_init, /* postconfiguration */
 NULL, /* create main configuration */
 NULL, /* init main configuration */
 NULL, /* create server configuration */
 NULL, /* merge server configuration */
 ngx_http_hello_create_loc_conf, /* create location configuration */
 NULL /* merge location configuration */
 };

注意:这里并没有提供 merge_loc_conf 函数,因为我们这个模块的配置指令已经确定只出现在 NGX_HTTP_LOC_CONF 中这一个层次上,不会发生需要合并的情况。

模块的定义

对于开发一个模块来说,我们都需要定义一个 ngx_module_t 类型的变量来说明这个模块本身的信息,从某种意义上来说,这是这个模块最重要的一个信息,它告诉了 Nginx 这个模块的一些信息,上面定义的配置信息,还有模块上下文信息,都是通过这个结构来告诉 Nginx 系统的,也就是加载模块的上层代码,都需要通过定义的这个结构,来获取这些信息。

我们先来看下 ngx_module_t 的定义

 typedef struct ngx_module_s ngx_module_t;
 struct ngx_module_s {
 ngx_uint_t ctx_index;
 ngx_uint_t index;
 ngx_uint_t spare0;
 ngx_uint_t spare1;
 ngx_uint_t abi_compatibility;
 ngx_uint_t major_version;
 ngx_uint_t minor_version;
 void *ctx;
 ngx_command_t *commands;
 ngx_uint_t type;
 ngx_int_t (*init_master)(ngx_log_t *log);
 ngx_int_t (*init_module)(ngx_cycle_t *cycle);
 ngx_int_t (*init_process)(ngx_cycle_t *cycle);
 ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
 void (*exit_thread)(ngx_cycle_t *cycle);
 void (*exit_process)(ngx_cycle_t *cycle);
 void (*exit_master)(ngx_cycle_t *cycle);
 uintptr_t spare_hook0;
 uintptr_t spare_hook1;
 uintptr_t spare_hook2;
 uintptr_t spare_hook3;
 uintptr_t spare_hook4;
 uintptr_t spare_hook5;
 uintptr_t spare_hook6;
 uintptr_t spare_hook7;
 };
 #define NGX_NUMBER_MAJOR 3
 #define NGX_NUMBER_MINOR 1
 #define NGX_MODULE_V1 0, 0, 0, 0, 
 NGX_DSO_ABI_COMPATIBILITY, NGX_NUMBER_MAJOR, NGX_NUMBER_MINOR
 #define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0

再看一下 hello 模块的模块定义。

 ngx_module_t ngx_http_hello_module = {
 NGX_MODULE_V1,
 &ngx_http_hello_module_ctx, /* module context */
 ngx_http_hello_commands, /* module directives */
 NGX_HTTP_MODULE, /* module type */
 NULL, /* init master */
 NULL, /* init module */
 NULL, /* init process */
 NULL, /* init thread */
 NULL, /* exit thread */
 NULL, /* exit process */
 NULL, /* exit master */
 NGX_MODULE_V1_PADDING
 };

模块可以提供一些回调函数给 Nginx,当 Nginx 在创建进程线程或者结束进程线程时进行调用。但大多数模块在这些时刻并不需要做什么,所以都简单赋值为 NULL。



Tags:Nginx   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
项目中,遇到了一个问题,就是PDF等文档不能够在线预览,预览时会报错。错误描述浏览器的console中,显示如下错误:nginx代理服务报Mixed Content: The page at ******** was loaded...【详细内容】
2021-12-17  Tags: Nginx  点击:(7)  评论:(0)  加入收藏
前言Nginx是前后端开发工程师必须掌握的神器。该神器有很多使用场景,比如反向代理、负载均衡、动静分离、跨域等等。把 Nginx下载下来,打开conf文件夹的nginx.conf文件,Nginx服...【详细内容】
2021-12-08  Tags: Nginx  点击:(18)  评论:(0)  加入收藏
最近客户有个新需求,就是想查看网站的访问情况,由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的页...【详细内容】
2021-10-09  Tags: Nginx  点击:(48)  评论:(0)  加入收藏
安全服务器是只允许所需数量的服务器。理想情况下,我们将通过单独启用其他功能来基于最小系统构建服务器。进行最少的配置也有助于调试。如果该错误在最小系统中不可用,则分别...【详细内容】
2021-09-26  Tags: Nginx  点击:(60)  评论:(0)  加入收藏
在今年的NGINX Sprint 2.0虚拟大会上,NGINX(来自流行的开源web服务器/负载均衡器和反向代理背后的公司F5),发布了NGINX现代应用参考架构(MARA)。该公司在一篇博客文章中说,这将帮...【详细内容】
2021-09-26  Tags: Nginx  点击:(61)  评论:(0)  加入收藏
Ubuntu下安装Nginx一、系统基本信息查看1、查看Ubuntu版本信息:使用命令:cat /proc/version 查看~$ cat /proc/versionLinux version 4.15.0-106-generic (buildd@lcy01-amd6...【详细内容】
2021-09-16  Tags: Nginx  点击:(60)  评论:(0)  加入收藏
出于安全审查或者对于系统安全性的要求,都要求我们生产环境部署的系统需要做一定的权限控制。那么如何简单快速地部署满足安全要求的权限系统呢?其实可以通过nginx的相关功能...【详细内容】
2021-09-07  Tags: Nginx  点击:(69)  评论:(0)  加入收藏
什么是NginxNginx(engine x)是一个高性能的HTTP和反向代理服务器,具有内存少,高并发特点强。1、处理静态文件,索引文件以及自动检索打开文件描述符缓冲2、无缓冲的反向代理加速...【详细内容】
2021-09-02  Tags: Nginx  点击:(70)  评论:(0)  加入收藏
本文适用于 php7.4+NGINX环境,适用于运行 wordpress 环境一、更新服务器sudo apt update二、命令快捷缩写设置通过ssh登录服务器,在用户目录下执行以下命令sudo nano .bashrca...【详细内容】
2021-08-31  Tags: Nginx  点击:(87)  评论:(0)  加入收藏
一、nginx正向代理介绍及配置(需要在客户端配置代理服务器进行指定网站访问)#模块 ngx_http_proxy_module: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy...【详细内容】
2021-08-16  Tags: Nginx  点击:(76)  评论:(0)  加入收藏
▌简易百科推荐
阿里云镜像源地址及安装网站地址https://developer.aliyun.com/mirror/centos?spm=a2c6h.13651102.0.0.3e221b111kK44P更新源之前把之前的国外的镜像先备份一下 切换到yumcd...【详细内容】
2021-12-27  干程序那些事    Tags:CentOS7镜像   点击:(1)  评论:(0)  加入收藏
前言在实现TCP长连接功能中,客户端断线重连是一个很常见的问题,当我们使用netty实现断线重连时,是否考虑过如下几个问题: 如何监听到客户端和服务端连接断开 ? 如何实现断线后重...【详细内容】
2021-12-24  程序猿阿嘴  CSDN  Tags:Netty   点击:(12)  评论:(0)  加入收藏
一. 配置yum源在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repovim /etc/yum.repos.d/google-chrome.repo按i进入编辑模式写入如下内容:[google-chrome]name=googl...【详细内容】
2021-12-23  有云转晴    Tags:chrome   点击:(7)  评论:(0)  加入收藏
一. HTTP gzip压缩,概述 request header中声明Accept-Encoding : gzip,告知服务器客户端接受gzip的数据 response body,同时加入以下header:Content-Encoding: gzip:表明bo...【详细内容】
2021-12-22  java乐园    Tags:gzip压缩   点击:(9)  评论:(0)  加入收藏
yum -y install gcc automake autoconf libtool makeadduser testpasswd testmkdir /tmp/exploitln -s /usr/bin/ping /tmp/exploit/targetexec 3< /tmp/exploit/targetls -...【详细内容】
2021-12-22  SofM    Tags:Centos7   点击:(7)  评论:(0)  加入收藏
Windows操作系统和Linux操作系统有何区别?Windows操作系统:需支付版权费用,(华为云已购买正版版权,在华为云购买云服务器的用户安装系统时无需额外付费),界面化的操作系统对用户使...【详细内容】
2021-12-21  卷毛琴姨    Tags:云服务器   点击:(6)  评论:(0)  加入收藏
参考资料:Hive3.1.2安装指南_厦大数据库实验室博客Hive学习(一) 安装 环境:CentOS 7 + Hadoop3.2 + Hive3.1 - 一个人、一座城 - 博客园1.安装hive1.1下载地址hive镜像路径 ht...【详细内容】
2021-12-20  zebra-08    Tags:Hive   点击:(9)  评论:(0)  加入收藏
以下是服务器安全加固的步骤,本文以腾讯云的CentOS7.7版本为例来介绍,如果你使用的是秘钥登录服务器1-5步骤可以跳过。1、设置复杂密码服务器设置大写、小写、特殊字符、数字...【详细内容】
2021-12-20  网安人    Tags:服务器   点击:(7)  评论:(0)  加入收藏
项目中,遇到了一个问题,就是PDF等文档不能够在线预览,预览时会报错。错误描述浏览器的console中,显示如下错误:nginx代理服务报Mixed Content: The page at ******** was loaded...【详细内容】
2021-12-17  mdong    Tags:Nginx   点击:(7)  评论:(0)  加入收藏
转自: https://kermsite.com/p/wt-ssh/由于格式问题,部分链接、表格可能会失效,若失效请访问原文密码登录 以及 通过密钥实现免密码登录Dec 15, 2021阅读时长: 6 分钟简介Windo...【详细内容】
2021-12-17  LaLiLi    Tags:SSH连接   点击:(16)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条