You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by to...@apache.org on 2021/05/11 08:53:02 UTC

[apisix] branch master updated: feat: add 50x html for error page (#4164)

This is an automated email from the ASF dual-hosted git repository.

tokers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new adc9977  feat: add 50x html for error page (#4164)
adc9977 is described below

commit adc9977dd0459be7ee5386b7269684b70d69f29b
Author: Peter Zhu <st...@gmail.com>
AuthorDate: Tue May 11 16:52:48 2021 +0800

    feat: add 50x html for error page (#4164)
---
 .gitignore                   |   1 +
 apisix/cli/html_page.lua     |  39 ++++++++++++
 apisix/cli/ngx_tpl.lua       |  39 ++++++++++++
 apisix/cli/ops.lua           |   9 +++
 apisix/init.lua              |  19 +++++-
 ci/ASF-Release.cfg           |   1 +
 t/APISIX.pm                  |  29 +++++++++
 t/error_page/50x.html        |  38 ++++++++++++
 t/error_page/error_page.t    | 141 +++++++++++++++++++++++++++++++++++++++++++
 t/lib/server.lua             |   9 +++
 t/node/upstream-status-5xx.t |   4 +-
 11 files changed, 325 insertions(+), 4 deletions(-)

diff --git a/.gitignore b/.gitignore
index 98b0b7e..92d7722 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,3 +74,4 @@ ci/openwhisk-utilities/
 # release tar package
 *.tgz
 release/*
+html/*
diff --git a/apisix/cli/html_page.lua b/apisix/cli/html_page.lua
new file mode 100644
index 0000000..f262ad8
--- /dev/null
+++ b/apisix/cli/html_page.lua
@@ -0,0 +1,39 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+return [=[
+<!DOCTYPE html>
+<html>
+<head>
+<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+<meta content="utf-8" http-equiv="encoding">
+<title>500 Internal Server Error</title>
+<style>
+    body {
+        width: 35em;
+        margin: 0 auto;
+        font-family: Tahoma, Verdana, Arial, sans-serif;
+    }
+</style>
+</head>
+<body>
+<h1>An error occurred.</h1>
+<p>You can report issue to <a href="https://github.com/apache/apisix/issues">APISIX</a></p>
+<p><em>Faithfully yours, <a href="https://apisix.apache.org/">APISIX</a>.</em></p>
+</body>
+</html>
+]=]
diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index c9c5d78..041a2d6 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -219,6 +219,9 @@ http {
     include mime.types;
     charset utf-8;
 
+    # error_page
+    error_page 500 @50x.html;
+
     {% if real_ip_header then %}
     real_ip_header {* real_ip_header *};
     {% print("\nDeprecated: apisix.real_ip_header has been moved to nginx_config.http.real_ip_header. apisix.real_ip_header will be removed in the future version. Please use nginx_config.http.real_ip_header first.\n\n") %}
@@ -290,6 +293,18 @@ http {
                 apisix.http_control()
             }
         }
+
+        location @50x.html {
+            set $from_error_page 'true';
+            try_files /50x.html $uri;
+            header_filter_by_lua_block {
+                apisix.http_header_filter_phase()
+            }
+
+            log_by_lua_block {
+                apisix.http_log_phase()
+            }
+        }
     }
     {% end %}
 
@@ -367,6 +382,18 @@ http {
                 apisix.http_admin()
             }
         }
+
+        location @50x.html {
+            set $from_error_page 'true';
+            try_files /50x.html $uri;
+            header_filter_by_lua_block {
+                apisix.http_header_filter_phase()
+            }
+
+            log_by_lua_block {
+                apisix.http_log_phase()
+            }
+        }
     }
     {% end %}
 
@@ -617,6 +644,18 @@ http {
             proxy_pass $upstream_mirror_host$request_uri;
         }
         {% end %}
+
+        location @50x.html {
+            set $from_error_page 'true';
+            try_files /50x.html $uri;
+            header_filter_by_lua_block {
+                apisix.http_header_filter_phase()
+            }
+
+            log_by_lua_block {
+                apisix.http_log_phase()
+            }
+        }
     }
     # http end configuration snippet starts
     {% if http_end_configuration_snippet then %}
diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua
index fbf0160..7b681a6 100644
--- a/apisix/cli/ops.lua
+++ b/apisix/cli/ops.lua
@@ -19,6 +19,7 @@ local etcd = require("apisix.cli.etcd")
 local util = require("apisix.cli.util")
 local file = require("apisix.cli.file")
 local ngx_tpl = require("apisix.cli.ngx_tpl")
+local html_page = require("apisix.cli.html_page")
 local profile = require("apisix.core.profile")
 local template = require("resty.template")
 local argparse = require("argparse")
@@ -586,6 +587,14 @@ Please modify "admin_key" in conf/config.yaml .
     if not ok then
         util.die("failed to update nginx.conf: ", err, "\n")
     end
+
+    local cmd_html = "mkdir -p " .. env.apisix_home .. "/html"
+    util.execute_cmd(cmd_html)
+
+    local ok, err = util.write_file(env.apisix_home .. "/html/50x.html", html_page)
+    if not ok then
+        util.die("failed to write 50x.html: ", err, "\n")
+    end
 end
 
 
diff --git a/apisix/init.lua b/apisix/init.lua
index 87da8bc..ae305f7 100644
--- a/apisix/init.lua
+++ b/apisix/init.lua
@@ -475,14 +475,13 @@ function _M.http_access_phase()
 
     set_upstream_host(api_ctx)
 
+    ngx_var.ctx_ref = ctxdump.stash_ngx_ctx()
     local up_scheme = api_ctx.upstream_scheme
     if up_scheme == "grpcs" or up_scheme == "grpc" then
-        ngx_var.ctx_ref = ctxdump.stash_ngx_ctx()
         return ngx.exec("@grpc_pass")
     end
 
     if api_ctx.dubbo_proxy_enabled then
-        ngx_var.ctx_ref = ctxdump.stash_ngx_ctx()
         return ngx.exec("@dubbo_pass")
     end
 end
@@ -490,11 +489,13 @@ end
 
 function _M.dubbo_access_phase()
     ngx.ctx = ctxdump.apply_ngx_ctx(ngx_var.ctx_ref)
+    ngx_var.ctx_ref = ''
 end
 
 
 function _M.grpc_access_phase()
     ngx.ctx = ctxdump.apply_ngx_ctx(ngx_var.ctx_ref)
+    ngx_var.ctx_ref = ''
 
     local api_ctx = ngx.ctx.api_ctx
     if not api_ctx then
@@ -534,6 +535,16 @@ end
 
 
 function _M.http_header_filter_phase()
+    if ngx_var.ctx_ref ~= '' then
+        -- prevent for the table leak
+        local stash_ctx = ctxdump.apply_ngx_ctx(ngx_var.ctx_ref)
+
+        -- internal redirect, so we should apply the ctx
+        if ngx_var.from_error_page == "true" then
+            ngx.ctx = stash_ctx
+        end
+    end
+
     core.response.set_header("Server", ver_header)
 
     local up_status = get_var("upstream_status")
@@ -620,6 +631,10 @@ end
 
 function _M.http_log_phase()
     local api_ctx = common_phase("log")
+    if not api_ctx then
+        return
+    end
+
     healthcheck_passive(api_ctx)
 
     if api_ctx.server_picker and api_ctx.server_picker.after_balance then
diff --git a/ci/ASF-Release.cfg b/ci/ASF-Release.cfg
index 10de19f..7efd557 100644
--- a/ci/ASF-Release.cfg
+++ b/ci/ASF-Release.cfg
@@ -88,6 +88,7 @@ grpcurl
 t/servroot
 t/lib/dubbo-backend/dubbo-backend-provider/target
 t/lib/dubbo-backend/dubbo-backend-interface/target
+html
 
 conf
 ci/openwhisk-utilities
diff --git a/t/APISIX.pm b/t/APISIX.pm
index c2a5359..68821bd 100644
--- a/t/APISIX.pm
+++ b/t/APISIX.pm
@@ -89,6 +89,7 @@ my $ssl_ecc_crt = read_file("t/certs/apisix_ecc.crt");
 my $ssl_ecc_key = read_file("t/certs/apisix_ecc.key");
 my $test2_crt = read_file("t/certs/test2.crt");
 my $test2_key = read_file("t/certs/test2.key");
+my $test_50x_html = read_file("t/error_page/50x.html");
 $user_yaml_config = <<_EOC_;
 apisix:
   node_listen: 1984
@@ -374,6 +375,8 @@ _EOC_
     lua_socket_log_errors off;
     client_body_buffer_size 8k;
 
+    error_page 500 \@50x.html;
+
     upstream apisix_backend {
         server 0.0.0.1;
         balancer_by_lua_block {
@@ -426,6 +429,18 @@ _EOC_
             more_clear_headers Date;
         }
 
+        location \@50x.html {
+            set \$from_error_page 'true';
+            try_files /50x.html \$uri;
+            header_filter_by_lua_block {
+                apisix.http_header_filter_phase()
+            }
+
+            log_by_lua_block {
+                apisix.http_log_phase()
+            }
+        }
+
         location = /v3/auth/authenticate {
             content_by_lua_block {
                 ngx.log(ngx.WARN, "etcd auth failed!")
@@ -512,6 +527,18 @@ _EOC_
             }
         }
 
+        location \@50x.html {
+            set \$from_error_page 'true';
+            try_files /50x.html \$uri;
+            header_filter_by_lua_block {
+                apisix.http_header_filter_phase()
+            }
+
+            log_by_lua_block {
+                apisix.http_log_phase()
+            }
+        }
+
         location /v1/ {
             content_by_lua_block {
                 apisix.http_control()
@@ -625,6 +652,8 @@ $ssl_ecc_key
 $test2_crt
 >>> ../conf/cert/test2.key
 $test2_key
+>>> 50x.html
+$test_50x_html
 $user_apisix_yaml
 _EOC_
 
diff --git a/t/error_page/50x.html b/t/error_page/50x.html
new file mode 100644
index 0000000..f3b9e20
--- /dev/null
+++ b/t/error_page/50x.html
@@ -0,0 +1,38 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+<meta content="utf-8" http-equiv="encoding">
+<title>500 Internal Server Error</title>
+<style>
+    body {
+        width: 35em;
+        margin: 0 auto;
+        font-family: Tahoma, Verdana, Arial, sans-serif;
+    }
+</style>
+</head>
+<body>
+<h1>An error occurred.</h1>
+<p>You can report issue to <a href="https://github.com/apache/apisix/issues">APISIX</a></p>
+<p><em>Faithfully yours, <a href="https://apisix.apache.org/">APISIX</a>.</em></p>
+</body>
+</html>
diff --git a/t/error_page/error_page.t b/t/error_page/error_page.t
new file mode 100644
index 0000000..6f154c1
--- /dev/null
+++ b/t/error_page/error_page.t
@@ -0,0 +1,141 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+use t::APISIX 'no_plan';
+
+log_level('debug');
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: set route with serverless-post-function plugin
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "plugins": {
+                        "serverless-post-function": {
+                            "functions" : ["return function() if ngx.var.http_x_test_status ~= nil then;ngx.exit(tonumber(ngx.var.http_x_test_status));end;end"]
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/*"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 2: test apisix with internal error code 500
+--- request
+GET /hello
+--- more_headers
+X-Test-Status: 500
+--- error_code: 500
+--- response_body_like
+.*apisix.apache.org.*
+
+
+
+=== TEST 3: test apisix with internal error code 502
+--- request
+GET /hello
+--- more_headers
+X-Test-Status: 502
+--- error_code: 502
+--- response_body eval
+qr/502 Bad Gateway/
+
+
+
+=== TEST 4: test apisix with internal error code 503
+--- request
+GET /hello
+--- more_headers
+X-Test-Status: 503
+--- error_code: 503
+--- response_body eval
+qr/503 Service Temporarily Unavailable/
+
+
+
+=== TEST 5: test apisix with internal error code 504
+--- request
+GET /hello
+--- more_headers
+X-Test-Status: 504
+--- error_code: 504
+--- response_body eval
+qr/504 Gateway Time-out/
+
+
+
+=== TEST 6: test apisix with upstream error code 500
+--- request
+GET /specific_status
+--- more_headers
+X-Test-Upstream-Status: 500
+--- error_code: 500
+--- response_body
+upstream status: 500
+
+
+
+=== TEST 7: delete route(id: 1)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, message = t('/apisix/admin/routes/1',
+                 ngx.HTTP_DELETE,
+                 nil,
+                 [[{
+                    "action": "delete"
+                }]]
+                )
+            ngx.say("[delete] code: ", code, " message: ", message)
+        }
+    }
+--- request
+GET /t
+--- response_body
+[delete] code: 200 message: passed
+--- no_error_log
+[error]
diff --git a/t/lib/server.lua b/t/lib/server.lua
index 5a1b454..984886e 100644
--- a/t/lib/server.lua
+++ b/t/lib/server.lua
@@ -103,6 +103,15 @@ function _M.plugin_proxy_rewrite_args()
 end
 
 
+function _M.specific_status()
+    local status = ngx.var.http_x_test_upstream_status
+    if status ~= nil then
+        ngx.status = status
+        ngx.say("upstream status: ", status)
+    end
+end
+
+
 function _M.status()
     ngx.say("ok")
 end
diff --git a/t/node/upstream-status-5xx.t b/t/node/upstream-status-5xx.t
index 7f42bec..c69b5cb 100644
--- a/t/node/upstream-status-5xx.t
+++ b/t/node/upstream-status-5xx.t
@@ -206,8 +206,8 @@ passed
 --- request
 GET /server_error
 --- error_code: 500
---- response_body eval
-qr/500 Internal Server Error/
+--- response_body_like
+.*apisix.apache.org.*
 --- error_log
 X-APISIX-Upstream-Status: 500