nginx服务器屏蔽上游错误码

平时的开发工作中,有时会遇到脚本权限不对导致403,文件被删除导致404,甚至后端业务异常导致5xx等情况,其实我们可以在服务器加上判断,检测当后端服务出现异常的时候前端返回一个指定的静态文件(也可以是一个动态资源)。

这样可以为一些关键业务(html或者动态资源,js等)配置此功能,当后端关键业务出现错误时,也会把一个指定的正确资源返回给用户。

想法自然是在nginx向客户端输出响应头时捕获信息,查看是不是异常,异常则跳转到指定文件

看了下nginx的第三方模块都没有实现这个功能,那还是自己来造轮子吧,最直接的开发方法是用openresty或者nginx+lua,nginx-lua提供了header_filter_by_lua挂载入口,可惜尝试下来却不行,仔细查看官方文档才发现这个入口里面禁用了一些关键IO操作的api

Uses Lua code specified in <lua-script-str> to define an output header filter.

Note that the following API functions are currently disabled within this context:

Output API functions (e.g., ngx.say and ngx.send_headers)
Control API functions (e.g., ngx.exit and ngx.exec)
Subrequest API functions (e.g., ngx.location.capture and ngx.location.capture_multi)
Cosocket API functions (e.g., ngx.socket.tcp and ngx.req.socket).
Here is an example of overriding a response header (or adding one if absent) in

只能做nginx模块开发来实现了。折腾了3个晚上,艰苦的调试过程就不提了,直接贴代码吧。

nginx配置文件如下:

location ~ \.php($|/) {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
        up_error_code   403 404 500 503 504 505;
        up_error_go     /ok.html;

}

location / {
        root   html;
        index  index.html index.htm;
        up_error_code   502;
        up_error_go     /ok.html;
}

其中:

up_error_code是需要屏蔽的后段错误码类型,支持多个;

up_error_go是需要跳转到的资源位置

(502错误需要在location /里面才能捕获到,这个非常奇怪,原因还不清楚,所以除了要在proxy的location里面设置其他错误过滤外也要在根目录下过滤502错误才行。)

代码(ngx_http_upstream_error_go_module.c)实现较为简单,具体如下:

/*
 * Copyright (C) Ciaos
 */

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

typedef struct {
    ngx_array_t     *error_codes;
    ngx_str_t       file_path;
} ngx_http_upstream_error_go_conf_t;

static void *ngx_http_upstream_error_go_create_conf(ngx_conf_t *cf);
static char *ngx_http_upstream_error_go_merge_conf(ngx_conf_t *cf, void *parent,void *child);

static char *ngx_http_upstream_error_go_set_code(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_http_upstream_error_go_set_file_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

static ngx_int_t ngx_http_upstream_error_go_init(ngx_conf_t *cf);

static ngx_command_t  ngx_http_upstream_error_go_commands[] = {
    { ngx_string("up_error_code"),
        NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
        ngx_http_upstream_error_go_set_code,
        NGX_HTTP_LOC_CONF_OFFSET,
        0,
        NULL },

    { ngx_string("up_error_go"),
        NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
        ngx_http_upstream_error_go_set_file_path,
        NGX_HTTP_LOC_CONF_OFFSET,
        0,
        NULL },

    ngx_null_command
};

static ngx_http_module_t  ngx_http_upstream_error_go_module_ctx = {
    NULL,                                  /* preconfiguration */
    ngx_http_upstream_error_go_init,              /* postconfiguration */

    NULL,                                  /* create main configuration */
    NULL,                                  /* init main configuration */

    NULL,                                  /* create server configuration */
    NULL,                                  /* merge server configuration */

    ngx_http_upstream_error_go_create_conf,       /* create location configration */
    ngx_http_upstream_error_go_merge_conf         /* merge location configration */
};

ngx_module_t  ngx_http_upstream_error_go_module = {
    NGX_MODULE_V1,
    &ngx_http_upstream_error_go_module_ctx,       /* module context */
    ngx_http_upstream_error_go_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
};

static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;

static ngx_int_t
ngx_http_upstream_error_go_header_filter(ngx_http_request_t *r)
{
    ngx_uint_t      e;
    ngx_uint_t      *ecode;
    ngx_http_upstream_error_go_conf_t *clcf;

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_upstream_error_go_module);
    if(clcf == NULL) {
        return NGX_ERROR;
    }

    if(clcf->error_codes){
        ecode = clcf->error_codes->elts;
        for(e = 0; e < clcf->error_codes->nelts; e ++){
            if(r->headers_out.status == *(ecode+e)){
                r->err_status = 0;
                ngx_str_set(&r->headers_out.status_line, "200 OK");
                ngx_http_internal_redirect(r, &clcf->file_path, &r->args);

                return NGX_ERROR;
            }
        }
    }

    return ngx_http_next_header_filter(r);
}

static ngx_int_t
ngx_http_upstream_error_go_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    return ngx_http_next_body_filter(r, in);
}

static char *
ngx_http_upstream_error_go_set_code(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_upstream_error_go_conf_t *clcf = conf;

    ngx_str_t       *value;
    ngx_uint_t      i;
    ngx_uint_t      *ecode;

    if(clcf->error_codes == NGX_CONF_UNSET_PTR) {
        clcf->error_codes = ngx_array_create(cf->pool, 4, sizeof(ngx_uint_t));
        if(clcf->error_codes == NULL)
        {
            return NGX_CONF_ERROR;
        }
    }
    value = cf->args->elts;
    for(i=1; i< cf->args->nelts; i++){
        ecode = ngx_array_push(clcf->error_codes);
        if(ecode == NULL) {
            return NGX_CONF_ERROR;
        }
        *ecode = ngx_atoi(value[i].data, value[i].len);
    }
    return NGX_CONF_OK;
}

static char *
ngx_http_upstream_error_go_set_file_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_upstream_error_go_conf_t *clcf = conf;
    ngx_str_t       *value;
    value = cf->args->elts;

    clcf->file_path = value[1];

    return NGX_CONF_OK;
}

static void *
ngx_http_upstream_error_go_create_conf(ngx_conf_t *cf)
{
    ngx_http_upstream_error_go_conf_t  *clcf;

    clcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_error_go_conf_t));
    if (clcf == NULL) {
        return NULL;
    }

    clcf->error_codes = NGX_CONF_UNSET_PTR;

    return clcf;
}

static char *
ngx_http_upstream_error_go_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_upstream_error_go_conf_t *prev = parent;
    ngx_http_upstream_error_go_conf_t *clcf = child;

    ngx_conf_merge_str_value(clcf->file_path, prev->file_path, "");
    ngx_conf_merge_ptr_value(clcf->error_codes, prev->error_codes, NULL);

    return NGX_CONF_OK;
}

static ngx_int_t
ngx_http_upstream_error_go_init(ngx_conf_t *cf)
{
    ngx_http_next_header_filter = ngx_http_top_header_filter;
    ngx_http_top_header_filter = ngx_http_upstream_error_go_header_filter;
    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_upstream_error_go_body_filter;

    return NGX_OK;
}

配置如下(config):

ngx_addon_name=ngx_http_upstream_error_go_module
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_upstream_error_go_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_upstream_error_go_module.c"

将源代码和配置文件放到某个目录下,编译nginx(版本1.7.4测试通过)带上此模块即可,测试工具可用Test::Nginx(perl -t t/test.t或prove -r t),测试代码如下

use Test::Nginx::Socket;
repeat_each(1);
plan tests => 1 * repeat_each() * blocks();

our $config = <<"_EOC_";
        location /foo {
            fastcgi_pass   127.0.0.1;
            up_error_code   403 404 502 500 503 504 505;
            up_error_go     /index.html;
        }
_EOC_

run_tests();

__DATA__

=== TEST 1: upstream 403
--- http_config eval
"
    server{
        listen  127.0.0.1:80;
        location /foo {
            return 403;
        }
    }
"
--- config eval: $::config
--- request
GET /foo
--- error_code: 200

=== TEST 2: upstream 404
--- http_config eval
"
    server{
        listen  127.0.0.1:80;
        location /foo {
            return 404;
        }
    }
"
--- config eval: $::config
--- request
GET /foo
--- error_code: 200

=== TEST 3: upstream 502
--- http_config
--- config eval: $::config
--- request
GET /foo
--- error_code: 200
时间: 2024-10-27 10:59:40

nginx服务器屏蔽上游错误码的相关文章

在Nginx服务器上屏蔽IP

采集和防止采集是一个经久不息的话题,一方面都想搞别人的东西,另一方面不想自己的东西被别人搞走. 本文介绍如何利用nginx屏蔽ip来实现防止采集,当然也可以通过iptable来实现. 1.查找要屏蔽的ip awk '{print $1}' nginx.access.log |sort |uniq -c|sort -n nginx.access.log 为日志文件, 会到如下结果,前面是ip的访问次数,后面是ip,很明显我们需要把访问次数多的ip并且不是蜘蛛的ip屏蔽掉,本例当中我们屏蔽掉 165

HP服务器重装centeos 6.3红屏错误码 Illegal Opcode

公司组装一个服务器要装centos 6.3 .出现一个问题 如果自动引导一切正常.如果手动分区重启后就会,红屏错误码 Illegal Opcode. 去网上问度娘各种不靠谱,有时说要 升级BIOS,从新做raid 了 各种不靠谱.自动引导正常表明绝对是系统安装问题. 试图 google 结果404 好吧 退而求其次 bing  直接bing Illegal Opcode 排除几个度娘过的中文站看到一个英文站 直接 翻译此页 终于找到句 HP ProLiant DL580 G5: Illegal

Nginx 之六: Nginx服务器的正向及反向代理功能

一:Nginx作为正向代理服务器: 1.正向代理:代理(proxy)服务也可以称为是正向代理,指的是将服务器部署在公司的网关,代理公司内部员工上外网的请求,可以起到一定的安全作用和管理限制作用,正向代理不支持从外网向内网访问资源,一般很少用,经本人测试,效果也不好,有很多页面打不开,在百度搜索的页面也无法返回. server { server_name localhost; resolver 202.106.0.20 8.8.8.8; #只能有一个resolve,但是可以用空格隔开,继续写下一个

http错误码大全

http错误码大全 http://en.wikipedia.org/wiki/List_of_HTTP_status_codes 响应码由三位十进制数字组成,它们出现在由HTTP服务器发送的响应的第一行.响应码分五种类型,由它们的第一位数字表示:1.1xx:信息,请求收到,继续处理2.2xx:成功,行为被成功地接受.理解和采纳3.3xx:重定向,为了完成请求,必须进一步执行的动作4.4xx:客户端错误,请求包含语法错误或者请求无法实现5.5xx:服务器错误,服务器不能实现一种明显无效的请求 下表

UTF-8,Unicode,GBK,希腊字母读法,ASCII码表,HTTP错误码,URL编码表,HTML特殊字符,汉字编码简明对照表

UNICODE,GBK,UTF-8区别 UNICODE,GBK,UTF-8区别    简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三种编码是一兼容的,同一个汉字,那三个码值是完全不一样的.如"汉"的uncode值与gbk就是不一样的,假设uncode为a040,gbk为b030,而uft-8码,就是把那个值表现的形式.utf-8码完全只针对uncode来组织的,如果GBK要转UTF-8必须先转uncode码,再转utf-8就O

CMPP错误码说明

与中国移动代码的对应关系. MI::zzzzSMSC返回状态报告的状态值为EXPIREDMJ:zzzzSMSC返回状态报告的状态值为DELETEDMK:zzzzSMSC返回状态报告的状态值为UNDELIVML:zzzzSMSC返回状态报告的状态值为ACCEPTDMM:zzzzSMSC返回状态报告的状态值为UNKNOWNMN:zzzzSMSC返回状态报告的状态值为REJECTD 回页首 CMPP发送失败代码对照表 值(4位,不足4位前面补0) 含义1 消息结构错2 命令字错误3 消息序列号重复4

转!!CMPP 网关错误码说明

与中国移动代码的对应关系. MI::zzzzSMSC返回状态报告的状态值为EXPIREDMJ:zzzzSMSC返回状态报告的状态值为DELETEDMK:zzzzSMSC返回状态报告的状态值为UNDELIVML:zzzzSMSC返回状态报告的状态值为ACCEPTDMM:zzzzSMSC返回状态报告的状态值为UNKNOWNMN:zzzzSMSC返回状态报告的状态值为REJECTD 回页首 CMPP发送失败代码对照表 值(4位,不足4位前面补0) 含义1 消息结构错2 命令字错误3 消息序列号重复4

XMPP协议错误码

302 重定向 尽管HTTP规定中包含八种不同代码来表示重定向,Jabber只用了其中一个(用来代替所有的重定向错误).不过Jabber代码302是为以后的功能预留的,目前还没有用到 400 坏请求 Jabber代码400用来通知Jabber客户端,一个请求因为其糟糕的语法不能被识别.例如,当一个Jabber客户端发送一个的订阅请求给它自己活发送一条没有包含"to"属性的消息,Jabber代码400就会产生. 401 未授权的 Jabber代码401用来通知Jabber客户端它们提供的

FreeBSD上构架Nginx服务器

这篇文章主要记录作者如何在FreeBSD上构架Nginx服务器.作者采用下载该程序的一个源代码包手动编译的方法,而不是使用包管理工具.这样做有两个原因:首先包质量不能保证,或无效或版本旧:其次需要在编译时对多种重要的选项进行配置. 另外,相关FreeBSD初始优化见博主之前的博文. 1          GCC Nginx是一个由C语言编写的程序,因此首先需要在系统上安装编译工具.我们采用常见GNU的GCC.确保系统上安装GCC: # gcc gcc: No input files specif