平时的开发工作中,有时会遇到脚本权限不对导致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,
,
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,
,
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 = ; e < clcf->error_codes->nelts; e ++){
if(r->headers_out.status == *(ecode+e)){
r->err_status = ;
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, , sizeof(ngx_uint_t));
if(clcf->error_codes == NULL)
{
return NGX_CONF_ERROR;
}
}
value = cf->args->elts;
for(i=; 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[]; 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

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

  1. nginx 客户端返回499的错误码

    我们服务器客户端一直有返回错误码499的日志,以前觉得比例不高,就没有仔细查过,最近有领导问这个问题,为什么耗时只有0.0几秒,为啥还499了?最近几天就把这个问题跟踪定位了一下,这里做个记录 网络架 ...

  2. nginx 499 错误码

    今天查看nginx的access log 文件,发现类似这种请求: [22/Apr/2014:14:01:12 +0800] "GET / HTTP/1.1" 499 0 &quo ...

  3. win7中 SQL server 2005无法连接到服务器,错误码:18456

    win7中 SQL server 2005无法连接到服务器,错误码:18456.. 数据库刚装完.我用Windows登陆  结果登陆不上去.. 选中SQL Server Management Stud ...

  4. 在Nginx服务器上屏蔽IP

    采集和防止采集是一个经久不息的话题,一方面都想搞别人的东西,另一方面不想自己的东西被别人搞走. 本文介绍如何利用nginx屏蔽ip来实现防止采集,当然也可以通过iptable来实现. 1.查找要屏蔽的 ...

  5. 错误码:2003 不能连接到 MySQL 服务器在 (10061)

    今天在ubuntu上安装了mysql服务器,在windows上用客户端软件连接mysql服务器时,出现错误: 错误码: 不能连接到 MySQL 服务器在 () 折腾来折腾去没搞好,防火墙也关了,330 ...

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

    公司组装一个服务器要装centos 6.3 .出现一个问题 如果自动引导一切正常.如果手动分区重启后就会,红屏错误码 Illegal Opcode. 去网上问度娘各种不靠谱,有时说要 升级BIOS,从 ...

  7. Nginx 之六: Nginx服务器的反向代理功能

    一:Nginx作为正向代理服务器: 1.正向代理:代理(proxy)服务也可以称为是正向代理,指的是将服务器部署在公司的网关,代理公司内部员工上外网的请求,可以起到一定的安全作用和管理限制作用,正向代 ...

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

    一:Nginx作为正向代理服务器: 1.正向代理:代理(proxy)服务也可以称为是正向代理,指的是将服务器部署在公司的网关,代理公司内部员工上外网的请求,可以起到一定的安全作用和管理限制作用,正向代 ...

  9. 【Fine原创】常见的HTTP错误码的具体含义整理

    常见的HTTP错误码的具体含义     "100" : Continue   客户端应当继续发送请求. "101" : witching Protocols   ...

随机推荐

  1. SQL serve创建与调用存储过程

    (1)创建 2编写存储过程(创建传参的存储过程)存储过程语法网络上很多不在累述 语法解析 Use Person 指定在那个数据库下建立存储过程 if (object_id('MyFunction', ...

  2. 代码风格——Cocos2d-x学习历程(四)

    1.Cocos2d-x拥有一个包含其他所有头文件的文件"cocos2d.h".通常,我们只需要在使用时包含这个头文件,就可以使用引擎的全部功能了. 2.Cocos2d-x的类都放置 ...

  3. 【转】Eclipse自动补全的设置方法

    转自:http://blog.csdn.net/xiadasong007/archive/2009/11/11/4799715.aspx 打开 Eclipse -> Window -> P ...

  4. tag标签添加删除并把值存入到一个input的value内

    html: <input type="text" id="tagValue" style="display: none;" /> ...

  5. netty中实现客户端首次连接绑定并非每次read检查的方法

    需求场景 客户端第一次连接时,将客户端存起来 重写 ChannelHandlerAdapter 的 handlerAdded 方法

  6. 写了个小爬虫,为何用上代理ip总是出现错误。

    import urllib.request import re import os import random import threading def url_open(url): #在第8到第12 ...

  7. Cortex-M3 动态加载二(RWPI数据无关实现)

    上一篇关于动态加载讲述的是M3下面的ropi的实现细节,这一篇则讲述RW段的实现细节以及系统加载RW段的思路,我在M3上根据这个思路可以实现elf的动态加载,当然进一步的可以优化很多东西,还可以研究将 ...

  8. 《Pointers On C》读书笔记(第四章 语句)

    1.空语句只包含一个分号,它本身并不执行任何任务,其适用的场合是语法要求出现一条完整的语句,但并不需要它执行任何任务. 2.C语言中并不存在专门的“赋值语句”,赋值就是一种操作,在表达式内进行.通过在 ...

  9. nyist0j 35 表达式求值

    题目链接:表达式求值 该题以前做过但是WA了,今天终于把他解决了,各种悲剧啊,又是考虑不周到啊................... 所以贴出来纪念一下,并作为一个警示 /**** ps:注意当遇到 ...

  10. Javascript 设计模式笔记

    设计模式太多了 还有些模式概念非常接近(比如观察者 中介者 和 事件发布/订阅模式) 构造器模式 var newObject = {} var newObject = new XXX(); 模块模式 ...