Nginx服務(wù)器中l(wèi)ocation配置的一些基本要點(diǎn)解析
在這一篇文章里,我將介紹nginx關(guān)于location的處理,大家都知道Nginx配置文件里面會(huì)有很多的location,nginx的配置指令的作用域可以分為 main,server,location這3個(gè)種,實(shí)際上這3者不是依次包含的關(guān)系,而是相互獨(dú)立的關(guān)系,比如一個(gè)只具有main級(jí)別作用域的指令,是不能寫(xiě)在某個(gè)server或者location內(nèi)的,模塊的某個(gè)指令可以同時(shí)具有main,server,location這3種作用域,另外每個(gè)模塊有 main,srv,loc這3個(gè)級(jí)別的配置,一個(gè)模塊的main級(jí)別的配置對(duì)所有的server和location都是共享的,srv級(jí)別的配置對(duì)所有 location都是共享的,location只有自己獨(dú)立的loc級(jí)別的配置,這就是為什么一個(gè)模塊的srv和loc級(jí)別的配置需要merge,而 main級(jí)別的配置不需要merge的原因。這里看起來(lái)有點(diǎn)繞,區(qū)分一下main,server,location分別作為一種作用域級(jí)別和一個(gè)主體,類似于形容詞和名字的區(qū)別,nginx的配置關(guān)系還是不難理解的。
一般來(lái)說(shuō)一個(gè)請(qǐng)求url過(guò)來(lái),nginx會(huì)將它解析到某一個(gè)location來(lái)處理。這個(gè)解析的過(guò)程實(shí)際上根據(jù)location的配置基本可以分為字符串匹配和正則表達(dá)式匹配這2種。對(duì)于location的組織方式,最簡(jiǎn)單的就是直接將它們保存為一個(gè)鏈表,解析url的時(shí)候一個(gè)一個(gè)遍歷即可找到相應(yīng)location,但是這樣效率太低,對(duì)像nginx這種高性能的服務(wù)器來(lái)說(shuō)是完全不可取的,nginx將字符串匹配的location組織成了一個(gè)三叉的字符串排序樹(shù),而且建立的時(shí)候也考慮了樹(shù)的平衡性。文章后面我講詳細(xì)介紹源碼的實(shí)現(xiàn)。
首先我來(lái)大概的介紹一下location的種類和匹配規(guī)則,以nginx wiki(http://wiki.nginx.org/HttpCoreModule#location)的例子做說(shuō)明:
location = / {
# matches the query / only.
[ configuration A ]
}
location / {
# matches any query, since all queries begin with /, but regular
# expressions and any longer conventional blocks will be
# matched first.
[ configuration B ]
}
location ^~ /images/ {
# matches any query beginning with /images/ and halts searching,
# so regular expressions will not be checked.
[ configuration C ]
}
location ~* \.(gif|jpg|jpeg)$ {
# matches any request ending in gif, jpg, or jpeg. However, all
# requests to the /images/ directory will be handled by
# Configuration C.
[ configuration D ]
}
location @named {
# Such locations are not used during normal processing of requests,
# they are intended only to process internally redirected requests (for example error_page, try_files).
[ configuration E ]
}
可以看到上面的例子中有5種不同類型的location,其中第4個(gè)帶 “~” 號(hào)前綴的為需要正則匹配的location,nginx在進(jìn)行url解析時(shí)對(duì)這5種不同類型的location具有不同的優(yōu)先級(jí)規(guī)則,大致的規(guī)則如下:
1,字符串精確匹配到一個(gè)帶 “=” 號(hào)前綴的location,則停止,且使用這個(gè)location的配置;
2,字符串匹配剩下的非正則和非特殊location,如果匹配到某個(gè)帶 "^~" 前綴的location,則停止;
3,正則匹配,匹配順序?yàn)閘ocation在配置文件中出現(xiàn)的順序。如果匹配到某個(gè)正則location,則停止,并使用這個(gè)location的配置;否則,使用步驟2中得到的具有最大字符串匹配的location配置。
例如,對(duì)下面的請(qǐng)求有:
1, / -> 精確匹配到第1個(gè)location,匹配停止,使用configuration A
2,/some/other/url -> 首先前綴部分字符串匹配到了第2個(gè)location,然后進(jìn)行正則匹配,顯然沒(méi)有匹配上,則使用第2個(gè)location的配置configurationB
3,/images /1.jpg -> 首先前綴部分字符串匹配到了第2個(gè)location,但是接著對(duì)第3個(gè)location也前綴匹配上了,而且這時(shí)已經(jīng)是配置文件里面對(duì)這個(gè)url的最大字符串匹配了,并且location帶有 "^~" 前綴,則不再進(jìn)行正則匹配,最終使用configuration C
4,/some/other/path/to/1.jpg -> 首先前綴部分同樣字符串匹配到了第2個(gè)location,然后進(jìn)行正則匹配,這時(shí)正則匹配成功,則使用congifuration D
nginx的url匹配規(guī)則實(shí)際上有點(diǎn)不妥,大部分情況下一個(gè)url必須先進(jìn)行字符串匹配,然后再做正則匹配,但是實(shí)際上如果先做正則匹配,沒(méi)有匹配上再 做字符串匹配,在很多情況下可以節(jié)省掉做字符串匹配的時(shí)間。不管怎樣,先來(lái)看一下nginx源碼里面的實(shí)現(xiàn),在介紹匹配location過(guò)程之前,先來(lái)介 紹一下nginx里面對(duì)location的組織方式,實(shí)際上在配置解析階段,nginx將字符串匹配的location和正則匹配的location分別 存儲(chǔ)在http core模塊的loc配置ngx_http_core_loc_conf_t結(jié)構(gòu)的下面2個(gè)字段:
ngx_http_location_tree_node_t *static_locations; (NGX_PCRE) ngx_http_core_loc_conf_t **regex_locations; if
從這2個(gè)字段的類型可以看出,字符串匹配的location被組織成了一個(gè)location tree,而正則匹配的location只是一個(gè)數(shù)組,
location tree和regex_locations數(shù)組建立過(guò)程在ngx_http_block中:
/* create location trees */
for (s = 0; s < cmcf->servers.nelts; s++) {
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
經(jīng)過(guò)配置的讀取之后,所有server都被保存在http core模塊的main配置中的servers數(shù)組中,而每個(gè)server里面的location都被按配置中出現(xiàn)的順序保存在http core模塊的loc配置的locations隊(duì)列中,上面的代碼中先對(duì)每個(gè)server的location進(jìn)行排序和分類處理,這一步發(fā)生在 ngx_http_init_location()函數(shù)中:
static ngx_int_t
ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_core_loc_conf_t *pclcf)
{
...
locations = pclcf->locations;
...
/* 按照類型排序location,排序完后的隊(duì)列: (exact_match 或 inclusive) (排序好的,如果某個(gè)exact_match名字和inclusive location相同,exact_match排在前面)
| regex(未排序)| named(排序好的) | noname(未排序)*/
ngx_queue_sort(locations, ngx_http_cmp_locations);
named = NULL;
n = 0;
#if (NGX_PCRE)
regex = NULL;
r = 0;
#endif
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
clcf = lq->exact ? lq->exact : lq->inclusive;
/* 由于可能存在nested location,也就是location里面嵌套的location,這里需要遞歸的處理一下當(dāng)前l(fā)ocation下面的nested location */
if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) {
return NGX_ERROR;
}
#if (NGX_PCRE)
if (clcf->regex) {
r++;
if (regex == NULL) {
regex = q;
}
continue;
}
#endif
if (clcf->named) {
n++;
if (named == NULL) {
named = q;
}
continue;
}
if (clcf->noname) {
break;
}
}
if (q != ngx_queue_sentinel(locations)) {
ngx_queue_split(locations, q, &tail);
}
/* 如果有named location,將它們保存在所屬server的named_locations數(shù)組中 */
if (named) {
clcfp = ngx_palloc(cf->pool,
(n + 1) * sizeof(ngx_http_core_loc_conf_t **));
if (clcfp == NULL) {
return NGX_ERROR;
}
cscf->named_locations = clcfp;
for (q = named;
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
*(clcfp++) = lq->exact;
}
*clcfp = NULL;
ngx_queue_split(locations, named, &tail);
}
#if (NGX_PCRE)
/* 如果有正則匹配location,將它們保存在所屬server的http core模塊的loc配置的regex_locations 數(shù)組中,
這里和named location保存位置不同的原因是由于named location只能存在server里面,而regex location可以作為nested location */
if (regex) {
clcfp = ngx_palloc(cf->pool,
(r + 1) * sizeof(ngx_http_core_loc_conf_t **));
if (clcfp == NULL) {
return NGX_ERROR;
}
pclcf->regex_locations = clcfp;
for (q = regex;
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
*(clcfp++) = lq->exact;
}
*clcfp = NULL;
ngx_queue_split(locations, regex, &tail);
}
#endif
return NGX_OK;
}
上面的步驟將正則匹配的location保存好了,location tree的建立在ngx_http_init_static_location_trees中進(jìn)行:
static ngx_int_t
ngx_http_init_static_location_trees(ngx_conf_t *cf,
ngx_http_core_loc_conf_t *pclcf)
{
ngx_queue_t *q, *locations;
ngx_http_core_loc_conf_t *clcf;
ngx_http_location_queue_t *lq;
locations = pclcf->locations;
if (locations == NULL) {
return NGX_OK;
}
if (ngx_queue_empty(locations)) {
return NGX_OK;
}
/* 這里也是由于nested location,需要遞歸一下 */
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
lq = (ngx_http_location_queue_t *) q;
clcf = lq->exact ? lq->exact : lq->inclusive;
if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
return NGX_ERROR;
}
}
/* join隊(duì)列中名字相同的inclusive和exact類型location,也就是如果某個(gè)exact_match的location名字和普通字符串匹配的location名字相同的話,
就將它們合到一個(gè)節(jié)點(diǎn)中,分別保存在節(jié)點(diǎn)的exact和inclusive下,這一步的目的實(shí)際是去重,為后面的建立排序樹(shù)做準(zhǔn)備 */
if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) {
return NGX_ERROR;
}
/* 遞歸每個(gè)location節(jié)點(diǎn),得到當(dāng)前節(jié)點(diǎn)的名字為其前綴的location的列表,保存在當(dāng)前節(jié)點(diǎn)的list字段下 */
ngx_http_create_locations_list(locations, ngx_queue_head(locations));
/* 遞歸建立location三叉排序樹(shù) */
pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0);
if (pclcf->static_locations == NULL) {
return NGX_ERROR;
}
return NGX_OK;
}
經(jīng)過(guò)ngx_http_init_location()函數(shù)處理之后,locations隊(duì)列已經(jīng)是排好序的了,建立三叉樹(shù)的過(guò)程的主要工作都在ngx_http_create_locations_list()和ngx_http_create_locations_tree()中完成,這2個(gè) 函數(shù)都是遞歸函數(shù),第1個(gè)函數(shù)遞歸locations隊(duì)列中的每個(gè)節(jié)點(diǎn),得到以當(dāng)前節(jié)點(diǎn)的名字為前綴的location,并保存在當(dāng)前節(jié)點(diǎn)的list字段 下,例如,對(duì)下列l(wèi)ocation:
location /xyz {
}
location = /xyz {
}
location /xyza {
}
location /xyzab {
}
location /xyzb {
}
location /abc {
}
location /efg {
}
location /efgaa {
}
排序的結(jié)果為/abc /efg /efgaa =/xyz /xyz /xyza /xyzab /xyzb,去重后結(jié)果為 /abc /efg /efgaa /xyz /xyza /xyzab/xyzb,ngx_http_create_locations_list()執(zhí)行后的結(jié)果為:

最后,來(lái)看下ngx_http_create_locations_tree函數(shù):
static ngx_http_location_tree_node_t *
ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
size_t prefix)
{
...
/* 根節(jié)點(diǎn)為locations隊(duì)列的中間節(jié)點(diǎn) */
q = ngx_queue_middle(locations);
lq = (ngx_http_location_queue_t *) q;
len = lq->name->len - prefix;
node = ngx_palloc(cf->pool,
offsetof(ngx_http_location_tree_node_t, name) + len);
if (node == NULL) {
return NULL;
}
node->left = NULL;
node->right = NULL;
node->tree = NULL;
node->exact = lq->exact;
node->inclusive = lq->inclusive;
node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
|| (lq->inclusive && lq->inclusive->auto_redirect));
node->len = (u_char) len;
ngx_memcpy(node->name, &lq->name->data[prefix], len);
/* 從中間節(jié)點(diǎn)開(kāi)始斷開(kāi) */
ngx_queue_split(locations, q, &tail);
if (ngx_queue_empty(locations)) {
/*
* ngx_queue_split() insures that if left part is empty,
* then right one is empty too
*/
goto inclusive;
}
/* 從locations左半部分得到左子樹(shù) */
node->left = ngx_http_create_locations_tree(cf, locations, prefix);
if (node->left == NULL) {
return NULL;
}
ngx_queue_remove(q);
if (ngx_queue_empty(&tail)) {
goto inclusive;
}
/* 從locations右半部分得到右子樹(shù) */
node->right = ngx_http_create_locations_tree(cf, &tail, prefix);
if (node->right == NULL) {
return NULL;
}
inclusive:
if (ngx_queue_empty(&lq->list)) {
return node;
}
/* 從list隊(duì)列得到tree子樹(shù) */
node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len);
if (node->tree == NULL) {
return NULL;
}
return node;
}
location tree節(jié)點(diǎn)的ngx_http_location_tree_node_s結(jié)構(gòu):
struct ngx_http_location_tree_node_s {
ngx_http_location_tree_node_t *left;
ngx_http_location_tree_node_t *right;
ngx_http_location_tree_node_t *tree;
ngx_http_core_loc_conf_t *exact;
ngx_http_core_loc_conf_t *inclusive;
u_char auto_redirect;
u_char len;
u_char name[1];
};
location tree結(jié)構(gòu)用到的是left,right,tree 這3個(gè)字段, location tree實(shí)際上是一個(gè)三叉的字符串排序樹(shù),而且這里如果某個(gè)節(jié)點(diǎn)只考慮左,右子樹(shù),它是一顆平衡樹(shù),它的建立過(guò)程有點(diǎn)類似于一顆平衡排序二叉樹(shù)的建立過(guò)程,先排序再用二分查找找到的節(jié)點(diǎn)順序插入,ngx_http_location_tree_node_s的tree節(jié)點(diǎn)也是一顆平衡排序樹(shù),它是用該節(jié)點(diǎn)由ngx_http_create_locations_list()得到的list建立的,也就是該節(jié)點(diǎn)的名字是它的tree子樹(shù)里面的所有節(jié)點(diǎn)名字的前綴,所以tree子樹(shù)里面的所有節(jié)點(diǎn)的名字不用保存公共前綴,而且查找的時(shí)候,如果是轉(zhuǎn)向tree節(jié)點(diǎn)的話,也是不需要再比較父節(jié)點(diǎn)的那段字符串了。
ngx_http_create_locations_tree()函數(shù)寫(xiě)的很清晰,它有一個(gè)參數(shù)是隊(duì)列l(wèi)ocations,它返回一顆三叉樹(shù),根節(jié)點(diǎn)為locations的中間節(jié)點(diǎn),其左子樹(shù)為locations隊(duì)列的左半部分建立的location tree,右子樹(shù)為location隊(duì)列的右半部分建立的tree,tree節(jié)點(diǎn)為該根節(jié)點(diǎn)的list隊(duì)列建立的tree。
最終建立的location tree如下(為了方便閱讀,圖中列出了tree節(jié)點(diǎn)的完整名字):

PS:關(guān)于 location modifier
1. =
這會(huì)完全匹配指定的 pattern ,且這里的 pattern 被限制成簡(jiǎn)單的字符串,也就是說(shuō)這里不能使用正則表達(dá)式。
Example:
server {
server_name jb51.net;
location = /abcd {
[…]
}
}
匹配情況:
http://jb51.net/abcd # 正好完全匹配 http://jb51.net/ABCD # 如果運(yùn)行 Nginx server 的系統(tǒng)本身對(duì)大小寫(xiě)不敏感,比如 Windows ,那么也匹配 http://jb51.net/abcd?param1¶m2 # 忽略查詢串參數(shù)(query string arguments),這里就是 /abcd 后面的 ?param1¶m2 http://jb51.net/abcd/ # 不匹配,因?yàn)槟┪泊嬖诜葱备埽╰railing slash),Nginx 不認(rèn)為這種情況是完全匹配 http://jb51.net/abcde # 不匹配,因?yàn)椴皇峭耆ヅ?
2. (None)
可以不寫(xiě) location modifier ,Nginx 仍然能去匹配 pattern 。這種情況下,匹配那些以指定的 patern 開(kāi)頭的 URI,注意這里的 URI 只能是普通字符串,不能使用正則表達(dá)式。
Example:
server {
server_name jb51.net;
location /abcd {
[…]
}
}
匹配情況:
http://jb51.net/abcd # 正好完全匹配 http://jb51.net/ABCD # 如果運(yùn)行 Nginx server 的系統(tǒng)本身對(duì)大小寫(xiě)不敏感,比如 Windows ,那么也匹配 http://jb51.net/abcd?param1¶m2 # 忽略查詢串參數(shù)(query string arguments),這里就是 /abcd 后面的 ?param1¶m2 http://jb51.net/abcd/ # 末尾存在反斜杠(trailing slash)也屬于匹配范圍內(nèi) http://jb51.net/abcde # 仍然匹配,因?yàn)?URI 是以 pattern 開(kāi)頭的
3. ~
這個(gè) location modifier 對(duì)大小寫(xiě)敏感,且 pattern 須是正則表達(dá)式
Example:
server {
server_name jb51.net;
location ~ ^/abcd$ {
[…]
}
}
匹配情況:
http://jb51.net/abcd # 完全匹配 http://jb51.net/ABCD # 不匹配,~ 對(duì)大小寫(xiě)是敏感的 http://jb51.net/abcd?param1¶m2 # 忽略查詢串參數(shù)(query string arguments),這里就是 /abcd 后面的 ?param1¶m2 http://jb51.net/abcd/ # 不匹配,因?yàn)槟┪泊嬖诜葱备埽╰railing slash),并不匹配正則表達(dá)式 ^/abcd$ http://jb51.net/abcde # 不匹配正則表達(dá)式 ^/abcd$
注意:對(duì)于一些對(duì)大小寫(xiě)不敏感的系統(tǒng),比如 Windows ,~ 和 ~* 都是不起作用的,這主要是操作系統(tǒng)的原因。
4. ~*
與 ~ 類似,但這個(gè) location modifier 不區(qū)分大小寫(xiě),pattern 須是正則表達(dá)式
Example:
server {
server_name jb51.net;
location ~* ^/abcd$ {
[…]
}
}
匹配情況:
http://jb51.net/abcd # 完全匹配 http://jb51.net/ABCD # 匹配,這就是它不區(qū)分大小寫(xiě)的特性 http://jb51.net/abcd?param1¶m2 # 忽略查詢串參數(shù)(query string arguments),這里就是 /abcd 后面的 ?param1¶m2 http://jb51.net/abcd/ # 不匹配,因?yàn)槟┪泊嬖诜葱备埽╰railing slash),并不匹配正則表達(dá)式 ^/abcd$ http://jb51.net/abcde # 不匹配正則表達(dá)式 ^/abcd$
5. ^~
匹配情況類似 2. (None) 的情況,以指定匹配模式開(kāi)頭的 URI 被匹配,不同的是,一旦匹配成功,那么 Nginx 就停止去尋找其他的 Location 塊進(jìn)行匹配了(與 Location 匹配順序有關(guān))
6. @
用于定義一個(gè) Location 塊,且該塊不能被外部 Client 所訪問(wèn),只能被 Nginx 內(nèi)部配置指令所訪問(wèn),比如 try_files or error_page
- Nginx配置指令location匹配符優(yōu)先級(jí)和安全問(wèn)題
- Nginx服務(wù)器中的location配置詳解
- 詳解nginx中l(wèi)ocation、rewrite用法總結(jié)
- nginx location中uri的截取的實(shí)現(xiàn)方法
- 詳解Nginx location 匹配規(guī)則
- nginx location 配置 正則表達(dá)式實(shí)例詳解
- nginx?location/區(qū)別詳解
- 詳解nginx rewrite和根據(jù)url參數(shù)location
- nginx?配置指令之location使用詳解
- 深入解析nginx路由location匹配規(guī)則及其優(yōu)先級(jí)
相關(guān)文章
關(guān)于nginx沒(méi)有跳轉(zhuǎn)到upstream地址的解決
這篇文章主要介紹了關(guān)于nginx沒(méi)有跳轉(zhuǎn)到upstream地址的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
詳解Nginx + Tomcat 反向代理 如何在高效的在一臺(tái)服務(wù)器部署多個(gè)站點(diǎn)
本篇文章主要介紹了詳解Nginx + Tomcat 反向代理 如何在高效的在一臺(tái)服務(wù)器部署多個(gè)站點(diǎn),具有一定的參考價(jià)值,有興趣的可以了解一下。2016-12-12
Nginx上對(duì)同一IP訪問(wèn)的特定URL進(jìn)行限流實(shí)現(xiàn)
要在Nginx上對(duì)同一IP訪問(wèn)的特定URL進(jìn)行限流,您可以使用ngx_http_limit_req_module模塊,本文就來(lái)介紹一下如何使用,具有一定的參考價(jià)值,感興趣的餓2024-01-01
Waiting for server respnse耗時(shí)過(guò)長(zhǎng)原因排查及解決
這篇文章主要給大家介紹了關(guān)于Waiting for server respnse耗時(shí)過(guò)長(zhǎng)原因排查及解決的相關(guān)資料,文中將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-05-05
Nginx實(shí)現(xiàn)動(dòng)態(tài)攔截非法訪問(wèn)ip的方法
最近在訪問(wèn)時(shí)不時(shí)會(huì)被暴力刷量,爬蟲(chóng)和惡意攻擊導(dǎo)致數(shù)據(jù)庫(kù),服務(wù)等癱瘓,所以本文介紹了在Nginx上實(shí)現(xiàn)一個(gè)動(dòng)態(tài)攔截IP的方法,具體是當(dāng)某個(gè)IP在1分鐘內(nèi)訪問(wèn)超過(guò)60次時(shí),將其加入Redis并攔截,攔截時(shí)間默認(rèn)1天,需要的朋友可以參考下2025-02-02
nginx部署vue項(xiàng)目的詳細(xì)圖文教程
很多小伙伴在做完Vue項(xiàng)目之后,想要部署到服務(wù)器上自己運(yùn)行試試,下面這篇文章主要給大家介紹了關(guān)于nginx部署vue項(xiàng)目的詳細(xì)圖文教程,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
shell腳本定時(shí)統(tǒng)計(jì)Nginx下access.log的PV并發(fā)送給API保存到數(shù)據(jù)庫(kù)
這篇文章主要介紹了shell腳本定時(shí)統(tǒng)計(jì)Nginx下access.log的PV并發(fā)送給API保存到數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方法 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09

