Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
站建設市場競爭越來越激烈,領先的網站建設技術是立足的根本,建站企業只有與時俱進,不斷更新適應市場的技術才能免遭淘汰。既然H5是網站建設時代的產物,就要懂得運用它來提升網站的質量,適應用戶的需求。網站建設運用H5技術有什么好處呢?下面就來看看。
一、頁面豐富。H5技術實現的網站也即是常說的響應式設計,改善了頁面多媒體元素的使用問題,之前建站頁面主張減少動畫、視頻等的使用,由于所占的網站資源空間多,導致頁面加載速度慢的情況,但如今使用H5建站,不僅可以大膽使用這些元素,且無需擔心瀏覽不順暢的問題,同時讓頁面顯得更加豐富,又能保證其整潔性。
二、利于網站優化。一個網站如果不能很好的利用互聯網資源,那么建站就沒有其價值所在,其中搜索引擎這個大平臺就是資源利用的一個好渠道,由此網站必然少不了優化。H5技術所使用的代碼程序相對來說要簡潔得多,且運用多媒體的情況下,對搜索引擎的抓取也是非常友好的,因此網站優化起來更加輕松。
三、提升用戶體驗。H5的出現,改善了網頁內容被插件束縛的局面,創造了豐富多彩的網站,滿足了用戶視覺上的審美要求,且能夠保證網站的加載速度,更重要的是當前的各種瀏覽器的推出,對于不同的用戶有不同的使用習慣,H5很好地兼容各種瀏覽器的,讓網站的呈現效果不會因設備的不同而改變,大大提高了用戶體驗。
四、增加網站流量。由于H5技術實現了網站跨平臺的運用,尤其移動設備的多樣化,包括各種屏幕大小的手機,平板等等,毫無疑問,在移動互聯網的趨勢下,大半的用戶流量將來源于移動端的用戶,H5網站的建設,輕松拓展了用戶瀏覽渠道,給網站增加流量。
本文由成都網站建設公司、成都網站設計制作公司、成都APP開發公司、成都響應式網站建設-新線加科技為您整理發布,希望能對你有所幫助!本文來自:http://www.scwbo.com/news/newsdetail101_403.html
次NGINX在嘗試處理客戶端請求時遇到錯誤,它都會返回一個錯誤。每個錯誤都包含一個HTTP響應代碼和一個簡短描述。錯誤通常通過簡單的默認HTML頁面顯示給用戶。
幸運的是,您可以配置NGINX以向您的站點或 Web 應用程序的用戶顯示自定義錯誤頁面。這可以使用 NGINX 的 error_page指令來實現,該指令用于定義將針對指定錯誤顯示的URI 。您還可以選擇使用它來修改發送給客戶端的響應標頭中的 HTTP 狀態代碼。
在本指南中,我們將展示如何配置NGINX以使用自定義錯誤頁面。
您可以將NGINX配置為使用單個自定義錯誤頁面來處理它返回給客戶端的所有錯誤。首先創建您的錯誤頁面。這是一個示例,一個顯示消息的簡單 HTML 頁面:
“Sorry, the page can't be loaded! Contact the site's administrator or support for assistance.” to a client.
示例 HTML Nginx 自定義頁面代碼。
<!DOCTYPE html><html><head><style type=text/css>* {
-webkit-box-sizing: border-box;
box-sizing: border-box;}body {
padding: 0;
margin: 0;}#notfound {
position: relative;
height: 100vh;}#notfound .notfound {
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);}.notfound {
max-width: 520px;
width: 100%;
line-height: 1.4;
text-align: center;}.notfound .notfound-error {
position: relative;
height: 200px;
margin: 0px auto 20px;
z-index: -1;}.notfound .notfound-error h1 {
font-family: 'Montserrat', sans-serif;
font-size: 200px;
font-weight: 300;
margin: 0px;
color: #211b19;
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);}@media only screen and (max-width: 767px) {
.notfound .notfound-error h1 {
font-size: 148px;
}}@media only screen and (max-width: 480px) {
.notfound .notfound-error {
height: 148px;
margin: 0px auto 10px;}.notfound .notfound-error h1 {
font-size: 120px;
font-weight: 200px;}.notfound .notfound-error h2 {
font-size: 30px;}.notfound a {
padding: 7px 15px;
font-size: 24px;}.h2 {
font-size: 148px;}}</style></head><body><div id="notfound">
<div class="notfound">
<h1>Sorry the page can't be loaded!</a></h1>
<div class="notfound-error">
<p>Contact the site's administrator or support for assistance.</p>
</div>
</div></div></body></html>
使用適當的名稱保存文件,例如error-page.html并關閉它。
接下來,將文件移動到您的文檔根目錄 ( /var/www/html/ )。如果該目錄不存在,您可以使用mkdir命令創建它,如下所示:
$ sudo mkdir -p /var/www/html/
$ sudo cp error-page.html /var/www/html/
然后使用error_page指令配置NGINX以使用自定義錯誤頁面。如圖所示,在/etc/nginx/snippets/下創建一個名為custom-error-page.conf的配置文件。
$ sudo mkdir /etc/nginx/snippets/
$ sudo vim /etc/nginx/snippets/custom-error-page.conf
向其中添加以下行:
error_page 404 403 500 503 /error-page.html;location=/error-page.html {
root /var/www/html;
internal;}
每次NGINX遇到任何指定的 HTTP 錯誤 404、403、500 和 503 時,此配置都會導致內部重定向到URI / error-page.html。位置上下文告訴NGINX在哪里可以找到錯誤頁面。
保存文件并關閉它。
現在在http上下文中包含該文件,以便所有服務器塊都使用/etc/nginx/nginx.conf文件中的錯誤頁面:
$ sudo vim /etc/nginx/nginx.conf
包含目錄告訴NGINX將配置包含在指定.conf文件中:
include snippets/custom-error-page.conf;
或者,您可以包含特定服務器塊(通常稱為vhost)的文件,例如/etc/nginx/conf.d/mywebsite.conf。在服務器上下文中添加上述包含指令: {}
保存您的NGINX配置文件并重新加載服務,如下所示:
$ sudo systemctl reload nginx.service
并從瀏覽器測試設置是否正常。
您還可以為NGINX中的每個 HTTP 錯誤設置不同的自定義錯誤頁面。
要在服務器上設置存儲庫,請運行以下命令:
$ sudo git clone https://github.com/denysvitali/nginx-error-pages /srv/http/default
$ sudo mkdir /etc/nginx/snippets/
$ sudo ln -s /srv/http/default/snippets/error_pages.conf /etc/nginx/snippets/error_pages.conf
$ sudo ln -s /srv/http/default/snippets/error_pages_content.conf /etc/nginx/snippets/error_pages_content.conf
接下來,在您的http上下文或每個服務器塊/虛擬主機中添加以下配置:
include snippets/error_pages.conf;
保存您的 NGINX 配置文件并重新加載服務,如下所示:
$ sudo systemctl reload nginx.service
此外,如果配置按預期工作,請從瀏覽器測試。在這個示例中,我們測試了 404 錯誤頁面。
這就是我們在本指南中為您提供的全部內容。NGINX 的error_page指令允許您在發生錯誤時將用戶重定向到定義的頁面或資源或 URL。它還可選地允許在對客戶端的響應中修改 HTTP 狀態代碼。
家好,我是 polarisxu。
前幾天我寫了一篇文章:Go項目實戰:一步步構建一個并發文件下載器,有小伙伴評論問,請求 https://studygolang.com/dl/golang/go1.16.5.src.tar.gz 為什么沒有返回 Accept-Ranges。在寫那篇文章時,我也試了,確實沒有返回,因此我以為它不支持。
但有一個小伙伴很認真,他改用 GET 方法請求這個地址,結果卻有 Accept-Ranges,于是就很困惑,問我什么原因。經過一頓操作猛如虎,終于知道原因了。記錄下排查過程,供大家參考!(小伙伴的留言可以查看那篇文章)
通過 curl 命令,分別用 GET 和 HEAD 方法請求這個地址,結果如下:
$ curl -X GET --head https://studygolang.com/dl/golang/go1.16.5.src.tar.gz
HTTP/1.1 303 See Other
Server: nginx
Date: Wed, 07 Jul 2021 09:09:35 GMT
Content-Length: 0
Connection: keep-alive
Location: https://golang.google.cn/dl/go1.16.5.src.tar.gz
X-Request-Id: 83ee595c-6270-4fb0-a2f1-98fdc4d315be
$ curl --head https://studygolang.com/dl/golang/go1.16.5.src.tar.gz
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 07 Jul 2021 09:09:44 GMT
Connection: keep-alive
X-Request-Id: f2ba473d-5bee-44c3-a591-02c358551235
雖然都沒有 Accept-Ranges,但有一個奇怪現象:一個狀態碼是 303,一個是 200。很顯然,303 是正確的,HEAD 為什么會是 200?
我以為是 Nginx 對 HEAD 請求做了特殊處理,于是直接訪問 Go 服務的方式(不經過 Nginx 代理),結果一樣。
于是,我用 Go 實現一個簡單的 Web 服務,Handler 里面也重定向。
func main() {
http.HandleFunc("/dl", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusSeeOther)
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World")
})
http.ListenAndServe(":2022", nil)
}
用 curl 請求 http://localhost:2022/dl,GET 和 HEAD 都返回 303。于是我懷疑是不是 Echo 框架哪里的問題(studygolang 使用 Echo 框架構建的)。
所以,我用 Echo 框架寫個 Web 服務測試:
func main() {
e := echo.New()
e.GET("/dl", func(ctx echo.Context) error {
return ctx.Redirect(http.StatusSeeOther, "/")
})
e.GET("/", func(ctx echo.Context) error {
return ctx.String(http.StatusOK, "Hello World!")
})
e.Logger.Fatal(e.Start(":2022"))
}
同樣用 curl 請求 http://localhost:2022/dl,GET 返回 303,而 HEAD 報 405 Method Not Allowed,這符合預期。我們的路由設置只允許 GET 請求。但為什么 studygolang 沒有返回 405,因為它也限制只能 GET 請求。
于是我對隨便一個地址發起 HEAD 請求,發現都返回 200,可見 HTTP 錯誤被“吞掉”了。查找 studygolang 的中間件,發現了這個:
func HTTPError() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
if err := next(ctx); err != nil {
if !ctx.Response().Committed {
if he, ok := err.(*echo.HTTPError); ok {
switch he.Code {
case http.StatusNotFound:
if util.IsAjax(ctx) {
return ctx.String(http.StatusOK, `{"ok":0,"error":"接口不存在"}`)
}
return Render(ctx, "404.html", nil)
case http.StatusForbidden:
if util.IsAjax(ctx) {
return ctx.String(http.StatusOK, `{"ok":0,"error":"沒有權限訪問"}`)
}
return Render(ctx, "403.html", map[string]interface{}{"msg": he.Message})
case http.StatusInternalServerError:
if util.IsAjax(ctx) {
return ctx.String(http.StatusOK, `{"ok":0,"error":"接口服務器錯誤"}`)
}
return Render(ctx, "500.html", nil)
}
}
}
return nil
}
}
}
這里對 404、403、500 錯誤都做了處理,但其他 HTTP 錯誤直接忽略了,導致最后返回了 200 OK。只需要在上面 switch 語句加一個 default 分支,同時把 err 原樣 return,采用系統默認處理方式:
default:
return err
這樣 405 Method Not Allowed 會正常返回。
同時,為了解決 HEAD 能用來判斷下載行為,針對下載路由,我加上了允許 HEAD 請求,這樣就解決了小伙伴們的困惑。
不知道大家發現沒有,通過 curl 請求 https://studygolang.com/dl/golang/go1.16.5.src.tar.gz 和 Go 代碼請求,結果是不一樣的:
$ curl -X GET --head https://studygolang.com/dl/golang/go1.16.5.src.tar.gz
HTTP/1.1 303 See Other
Server: nginx
Date: Thu, 08 Jul 2021 02:05:10 GMT
Content-Length: 0
Connection: keep-alive
Location: https://golang.google.cn/dl/go1.16.5.src.tar.gz
X-Request-Id: 14d741ca-65c1-4b05-90b8-bef5c8b5a0a3
返回的是 303 重定向,自然沒有 Accept-Ranges 頭。
但改用如下 Go 代碼:
resp, err := http.Get("https://studygolang.com/dl/golang/go1.16.5.src.tar.gz")
if err != nil {
fmt.Println("get err", err)
return
}
fmt.Println(resp)
fmt.Println("ranges", resp.Header.Get("Accept-Ranges"))
返回的是 200,且有 Accept-Ranges 頭。可以猜測,應該是 Go 根據重定向遞歸請求重定向后的地址。可以查看源碼確認下。
通過這個可以看到:https://docs.studygolang.com/src/net/http/client.go?s=20406:20458#L574,核心代碼如下(比較容易看懂):
// 循環處理所有需要處理的 url(包括重定向后的)
for {
// For all but the first request, create the next
// request hop and replace req.
if len(reqs) > 0 {
// 如果是重定向,請求重定向地址
loc := resp.Header.Get("Location")
if loc == "" {
resp.closeBody()
return nil, uerr(fmt.Errorf("%d response missing Location header", resp.StatusCode))
}
u, err := req.URL.Parse(loc)
if err != nil {
resp.closeBody()
return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err))
}
host := ""
if req.Host != "" && req.Host != req.URL.Host {
// If the caller specified a custom Host header and the
// redirect location is relative, preserve the Host header
// through the redirect. See issue #22233.
if u, _ := url.Parse(loc); u != nil && !u.IsAbs() {
host = req.Host
}
}
ireq := reqs[0]
req = &Request{
Method: redirectMethod,
Response: resp,
URL: u,
Header: make(Header),
Host: host,
Cancel: ireq.Cancel,
ctx: ireq.ctx,
}
if includeBody && ireq.GetBody != nil {
req.Body, err = ireq.GetBody()
if err != nil {
resp.closeBody()
return nil, uerr(err)
}
req.ContentLength = ireq.ContentLength
}
// Copy original headers before setting the Referer,
// in case the user set Referer on their first request.
// If they really want to override, they can do it in
// their CheckRedirect func.
copyHeaders(req)
// Add the Referer header from the most recent
// request URL to the new one, if it's not https->http:
if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" {
req.Header.Set("Referer", ref)
}
err = c.checkRedirect(req, reqs)
// Sentinel error to let users select the
// previous response, without closing its
// body. See Issue 10069.
if err == ErrUseLastResponse {
return resp, nil
}
// Close the previous response's body. But
// read at least some of the body so if it's
// small the underlying TCP connection will be
// re-used. No need to check for errors: if it
// fails, the Transport won't reuse it anyway.
const maxBodySlurpSize = 2 << 10
if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
io.CopyN(io.Discard, resp.Body, maxBodySlurpSize)
}
resp.Body.Close()
if err != nil {
// Special case for Go 1 compatibility: return both the response
// and an error if the CheckRedirect function failed.
// See https://golang.org/issue/3795
// The resp.Body has already been closed.
ue := uerr(err)
ue.(*url.Error).URL = loc
return resp, ue
}
}
reqs = append(reqs, req)
var err error
var didTimeout func() bool
if resp, didTimeout, err = c.send(req, deadline); err != nil {
// c.send() always closes req.Body
reqBodyClosed = true
if !deadline.IsZero() && didTimeout() {
err = &httpError{
// TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancellation/
err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
timeout: true,
}
}
return nil, uerr(err)
}
// 確認重定向行為
var shouldRedirect bool
redirectMethod, shouldRedirect, includeBody = redirectBehavior(req.Method, resp, reqs[0])
if !shouldRedirect {
return resp, nil
}
req.closeBody()
}
可以進一步看 redirectBehavior 函數 https://docs.studygolang.com/src/net/http/client.go?s=20406:20458#L497:
func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirectMethod string, shouldRedirect, includeBody bool) {
switch resp.StatusCode {
case 301, 302, 303:
redirectMethod = reqMethod
shouldRedirect = true
includeBody = false
// RFC 2616 allowed automatic redirection only with GET and
// HEAD requests. RFC 7231 lifts this restriction, but we still
// restrict other methods to GET to maintain compatibility.
// See Issue 18570.
if reqMethod != "GET" && reqMethod != "HEAD" {
redirectMethod = "GET"
}
case 307, 308:
redirectMethod = reqMethod
shouldRedirect = true
includeBody = true
// Treat 307 and 308 specially, since they're new in
// Go 1.8, and they also require re-sending the request body.
if resp.Header.Get("Location") == "" {
// 308s have been observed in the wild being served
// without Location headers. Since Go 1.7 and earlier
// didn't follow these codes, just stop here instead
// of returning an error.
// See Issue 17773.
shouldRedirect = false
break
}
if ireq.GetBody == nil && ireq.outgoingLength() != 0 {
// We had a request body, and 307/308 require
// re-sending it, but GetBody is not defined. So just
// return this response to the user instead of an
// error, like we did in Go 1.7 and earlier.
shouldRedirect = false
}
}
return redirectMethod, shouldRedirect, includeBody
}
很清晰了吧。
很開心,還是有讀者很認真的在看我的文章,在跟著動手實踐,還對其中的點提出質疑。希望通過這篇文章,大家能夠對 HTTP 協議有更深的認識,同時體會問題排查的思路。
有其他問題,也歡迎留言交流!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。