iris,context源碼分析


// 上下文是服務器用於所有客戶端的中間人 "對象"。
//
// 對於每一個新的連接,會從 sync.Pool 中獲取一個新上下文對象。
// 上下文是 iris 的 http 流中最重要的部分。
//
// 開發者發送響應到客戶端的請求通過一個上下文。
// 開發者獲取請求信息從客戶端的請求上下文中。
//
// context 是 context.Context 子包的一個實現。
// context.Context 是很好擴展,所以開發者可以按照實際所需重寫它的方法。
type Context interface {
// ResponseWriter 如期返回一個兼容 http.ResponseWriter 的 響應writer。
ResponseWriter() ResponseWriter
// ResetResponseWriter 應該改變或者升級上下文的 ResponseWriter。
ResetResponseWriter(ResponseWriter)

// Request 方法如期返回原始的 *http.Request。
Request() *http.Request

// SetCurrentRouteName 方法設置內部路由名稱,為了當開發者調用
// `GetCurrentRoute()` 方法的時候能夠正確返回當前 「只讀」 路由。
// 它使用 Router 初始化,如果你手動更改了名稱,除了當你是使用`GetCurrentRoute()`
// 的時候將獲取到其他路由,其它沒啥變化。
// 為了從上下文中執行一個不同的路徑,你應該使用 `Exec` 函數,
// 或者通過 `SetHandlers/AddHandler` 函數改變處理方法。

SetCurrentRouteName(currentRouteName string)
// GetCurrentRoute 返回當前注冊到當前請求路徑的 「只讀」路由。
GetCurrentRoute() RouteReadOnly

// AddHandler 可以在服務時添加處理方法到當前請求,但是這些處理方法不會持久化到路由。
//
// Router 將會調用這些添加到某個路由的處理方法。如果 AddHandler 被調用,
// 那么處理方法將被添加到已經定義的路由的處理方法的后面。
AddHandler(...Handler)
// SetHandlers 替換所有原有的處理方法。
SetHandlers(Handlers)
// Handlers 記錄當前的處理方法。
Handlers() Handlers

// HandlerIndex 設置當前上下文處理方法鏈中當前索引。
// 如果傳入 -1 ,不會當前索引。
//
// 也可以查看 Handlers(), Next() and StopExecution()。
HandlerIndex(n int) (currentIndex int)
// HandlerName 返回當前路由名稱,方便調試。
HandlerName() string
// Next 調用從處理方法鏈中選擇剩下的進行調用,他應該被用於一個中間件中。
//
// 提醒:自定義的上下文應該重寫這個方法,以便能夠傳入他自己的 context.Context 實現。
Next()
// NextHandler 從處理鏈中返回下一個處理方法(但不執行)。
//
// 為了執行下一個 ,可以使用 .Skip() 跳過某個處理方法。
NextHandler() Handler
// Skip 從處理鏈中 忽略/跳過 下一個處理方法。
// 它應該在中間件內使用。
Skip()
// 如果調用了 StopExecution ,接下來的 .Next 調用將被局略。
StopExecution()
// IsStopped 檢查當前位置的Context是否是255, 如果是, 則返回true, 意味着 StopExecution() 被調用了。
IsStopped() bool

// +------------------------------------------------------------+
// | 當前的 "user/request" 存儲 |
// | 處理方法之間共享信息 - Values(). |
// | 保存並獲取路徑參數 - Params() |
// +------------------------------------------------------------+

// Params 返回當前URL中的命名參數。命名的路徑參數是被保存在這里的。
// 這個存儲對象隨着整個上下文,存活於每個請求聲明周期。
Params() *RequestParams

// Values 返回當前 「用戶」的存儲信息。
// 命名路徑參數和任何可選數據可以保存在這里。
// 這個存儲對象,也是存在於整個上下文,每個請求的聲明周期中。
//
// 你可以用這個函數設置和獲取用於在處理方法和中間件之間共享信息的局部值。
Values() *memstore.Store
// Translate 是 i18n 函數,用於本地化。它調用 Get("translate") 返回翻譯值。
//
// 示例:https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
Translate(format string, args ...interface{}) string

// +------------------------------------------------------------+
// | 路徑, 主機, 子域名, IP, HTTP 頭 等 |
// +------------------------------------------------------------+

// Method 返回 request.Method, 客戶端的請求方法。
Method() string
// Path 返回完整請求路徑,如果 EnablePathEscape 為 True,將會轉義。
Path() string
// RequestPath 返回轉義過的請求完整路徑。
RequestPath(escape bool) string

// Host 返回當前URL的主機部分。
Host() string
// Subdomain 返回當前請求的子域名,如果有。
// 提醒,這個方法可能在某些情況下不能正常使用。
Subdomain() (subdomain string)
// RemoteAddr 嘗試解析並返回客戶端正式IP。
//
// 基於允許的頭名稱,可以通過 Configuration.RemoteAddrHeaders 修改。
//
// 如果基於這些請求頭的解析失敗,將會 Request 的 `RemoteAddr` 字段,它在 Http 處理方法之前有 server 填充。
//
// 查看 `Configuration.RemoteAddrHeaders`,
// `Configuration.WithRemoteAddrHeader(...)`,
// `Configuration.WithoutRemoteAddrHeader(...)` 獲取更多信息。
RemoteAddr() string
// GetHeader 返回指定的請求頭值。
GetHeader(name string) string
// IsAjax 返回這個請求是否是一個 'ajax request'( XMLHttpRequest)。
//
// 不能百分之百確定一個請求是否是Ajax模式。
// 永遠不要信任來自客戶端的數據,他們很容易被篡改。
//
// 提醒,"X-Requested-With" 頭可以被任何客戶端修改,對於十分嚴重的情況,不要依賴於 IsAjax。
// 試試另外的鑒別方式,例如,內容類型(content-type)。
// 有很多描述這些問題的博客並且提供了很多不同的解決方案,這就是為什么說 `IsAjax`
// 太簡單,只能用於一般目的。
//
// 更多請看: https://developer.mozilla.org/en-US/docs/AJAX
// 以及: https://xhr.spec.whatwg.org/
IsAjax() bool

// +------------------------------------------------------------+
// | 響應頭助手 |
// +------------------------------------------------------------+

// Header 添加響應頭到響應 writer。
Header(name string, value string)

// ContentType 設置響應頭 "Content-Type" 為 'cType'。
ContentType(cType string)
// GetContentType 返回響應頭 "Content-Type" 的值。
GetContentType() string

// StatusCode 設置響應狀態碼。
// 也可查看 .GetStatusCode。
StatusCode(statusCode int)
// GetStatusCode 返回當前響應的狀態碼。
// 也可查閱 StatusCode。
GetStatusCode() int

// Redirect 發送一個重定向響應到客戶端,接受兩個參數,字符串和可選的證書。
// 第一個參數是重定向的URL,第二個是重定向狀態碼,默認是302。
// 如果必要,你可以設置為301,代表永久轉義。
Redirect(urlToRedirect string, statusHeader ...int)

// +------------------------------------------------------------+
// | 各種請求和 POST 數據 |
// +------------------------------------------------------------+

// URLParam 返回請求中的參數,如果有。
URLParam(name string) string
// URLParamInt 從請求返回 int 類型的URL參數,如果解析失敗,返回錯誤。
URLParamInt(name string) (int, error)
// URLParamInt64 從請求返回 int64 類型的參數,如果解析失敗,返回錯誤。
URLParamInt64(name string) (int64, error)
// URLParams 返回請求查詢參數映射,如果沒有,返回為空。
URLParams() map[string]string

// FormValue 返回一個表單值。
FormValue(name string) string
// FormValues 從 data,get,post 和 查詢參數中返回所有的數據值以及他們的鍵。
//
// 提醒: 檢查是否是 nil 是很有必要的。
FormValues() map[string][]string
// PostValue 僅僅根據名稱返回表單的post值,類似於 Request.PostFormValue。
PostValue(name string) string
// FormFile 返回鍵指定的第一個文件。
// 如果有必要,FormFile 調用 ctx.Request.ParseMultipartForm 和 ParseForm。
//
// 類似於 Request.FormFile.
FormFile(key string) (multipart.File, *multipart.FileHeader, error)

// +------------------------------------------------------------+
// | 自定義 HTTP 錯誤 |
// +------------------------------------------------------------+

// NotFound 發送一個 404 錯誤到客戶端,使用自定義的錯誤處理方法。
// 如果你不想剩下的處理方法被執行,你可能需要去調用 ctx.StopExecution()。
// 你可以將錯誤碼改成更具體的,例如:
// users := app.Party("/users")
// users.Done(func(ctx context.Context){ if ctx.StatusCode() == 400 { /* custom error code for /users */ }})
NotFound()

// +------------------------------------------------------------+
// | Body Readers |
// +------------------------------------------------------------+

// SetMaxRequestBodySize 設置請求體大小的上限,應該在讀取請求體之前調用。
SetMaxRequestBodySize(limitOverBytes int64)

// UnmarshalBody 讀取請求體,並把它綁定到一個任何類型或者指針的值。
// 使用實例: context.ReadJSON, context.ReadXML。
UnmarshalBody(v interface{}, unmarshaler Unmarshaler) error
// ReadJSON 從請求體讀取 JSON,並把它綁定到任何json有效類型的值。
ReadJSON(jsonObject interface{}) error
// ReadXML 從請求體讀取 XML,並把它綁定到任何xml有效類型的值。
ReadXML(xmlObject interface{}) error
// ReadForm 是用表單數據綁定 formObject,支持任何類型的結構體。
ReadForm(formObject interface{}) error

// +------------------------------------------------------------+
// | Body (raw) Writers |
// +------------------------------------------------------------+

// Write 將數據作為一個HTTP響應的一部分寫入連接。
//
// 如果 WriteHeader 還沒有調用,Write 將在 寫入數據之前調用 WriteHeader(http.StatusOK)。
// 如果 Header 沒有 Content-Type,Write 添加一個 Content-Type,設置為寫入數據的前
// 512 字節的類型。
//
// 取決於 HTTP 版本和客戶端,調用 Write 或者 WriteHeader 可能組織以后讀取 Request.Body。
// 對於 HTTP/1.x 請求,處理方法應該在寫入響應之前讀取所有必要的請求體數據。一旦 HTTP 頭被清掉
// (顯示調用 Flusher.Flush 或者寫入了足夠的數據觸發了清空操作),請求體可能變得不可用。
// 對於 HTTP/2 請求,Go HTTP 服務器允許在寫入響應的同時讀取請求體。然而,這種行為可能不被所有
// HTTP/2 客戶端支持。處理方法應該盡可能讀取最大量的數據在寫入之前。
Write(body []byte) (int, error)
// Writef 根據格式聲明器格式化,然后寫入響應。
//
// 返回寫入的字節數量以及任何寫入錯誤。
Writef(format string, args ...interface{}) (int, error)
// WriteString 將一個簡單的字符串寫入響應。
//
// 返回寫入的字節數量以及任何寫入錯誤。
WriteString(body string) (int, error)
// WriteWithExpiration 很像 Write,但是它發送了一個失效時間,它會被每個包級別的
// `StaticCacheDuration` 字段刷新。
WriteWithExpiration(body []byte, modtime time.Time) (int, error)
// StreamWriter 注冊給定的流用於發布響應體。
//
// 這個函數可能被用於一下這些情況:
//
// * 如果響應體太大(超過了iris.LimitRequestBodySize)
// * 如果響應體是慢慢從外部資源流入
// * 如果響應體必須分片流向客戶端(例如 `http server push`)
StreamWriter(writer func(w io.Writer) bool)

// +------------------------------------------------------------+
// | 帶壓縮的 Body Writers |
// +------------------------------------------------------------+
// 如果客戶端支持 gzip 壓縮,ClientSupportsGzip 返回 true。
ClientSupportsGzip() bool
// WriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
// WriteGzip 接受壓縮成 gzip 格式的字節然后發送給客戶端,並返回寫入的字節數量和錯誤(如果錯誤不支持 gzip 格式)
//
// 這個函數寫入臨時的 gzip 內容,ResponseWriter 不會改變。
WriteGzip(b []byte) (int, error)
// TryWriteGzip 接受 gzip 格式壓縮的字節,然后發送給客戶端。
// 如果客戶端不支持 gzip,就按照他們原來未壓縮的樣子寫入。
//
// 這個函數寫入臨時的 gzip 內容,ResponseWriter 不會改變。
TryWriteGzip(b []byte) (int, error)
// GzipResponseWriter converts the current response writer into a response writer
// GzipResponseWriter 將當前的響應 writer 轉化為一個 gzip 響應 writer。
// 當它的 .Write 方法被調用的時候,數據被壓縮成 gzip 格式然后把他們寫入客戶端。
//
// 也可以使用 .Disable 禁用以及使用 .ResetBody 回滾到常規的響應寫入器。
GzipResponseWriter() *GzipResponseWriter
// Gzip 開啟或者禁用 gzip 響應寫入器,如果客戶端支持 gzip 壓縮,所以接下來的響應數據將被作為
// 壓縮的 gzip 數據發送給客戶端。
Gzip(enable bool)

// +------------------------------------------------------------+
// | 富文本內容渲染器 |
// +------------------------------------------------------------+

// ViewLayout 設置 「布局」選項,如果隨后在相同的請求中 .View 被調用。
// 當需要去改變或者設置處理鏈中前一個方法的布局時很有用。
//
// 注意 'layoutTmplFile' 參數可以被設置為 iris.NoLayout 或者 view.NoLayout 去禁用某個試圖渲染動作的布局。
// 它禁用了配置項的布局屬性。
//
// 也可查看 .ViewData 和 .View。
//
// 示例:https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
ViewLayout(layoutTmplFile string)

// ViewData 保存一個或者多個鍵值對為了在后續的 .View 被調用的時候使用。
// 當需要處理鏈中前一個處理器的模板數據的時候是很有用的。
//
// 如果 .View 的綁定參數不是 nil 也不是 map 類型,這些數據就會被忽略,綁定是有優先級的,所以住路由的處理方法仍然有效。
// 如果綁定是一個map或者context.Map,這些數據然后就被添加到視圖數據然后傳遞給模板。
//
// .View 調用之后,這些數據不會被丟掉,為了在必要的時候重用(再次聲明,同一個請求中),為了清除這些數據,開發者可以調用
// ctx.Set(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey(), nil)。
//
// 如果 'key' 是空的,然后 值被作為它的(struct 或者 map)添加,並且開發者不能添加其他值。
//
// 推薦查看 .ViewLayout 和 .View。
//
// 示例:https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
ViewData(key string, value interface{})

// GetViewData 返回 `context#ViewData` 注冊的值。
// 返回值是 `map[string]interface{}` 類型,這意味着如果一個自定義的結構體被添加到 ViewData, 這個函數將把它解析成
// map,如果失敗返回 nil。
// 如果不同類型的值或者沒有數據通過 `ViewData` 注冊,檢查是否為nil總是好的編程規范。
//
// 類似於 `viewData := ctx.Values().Get("iris.viewData")` 或者
// `viewData := ctx.Values().Get(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey())`。
GetViewData() map[string]interface{}

// View 基於適配的視圖引擎渲染模板。第一個參數是接受相對於視圖引擎目錄的文件名,
// 例如如果目錄是 "./templates",想要渲染: "./templates/users/index.html"
// 你應該傳遞 "users/index.html" 作為文件名參數。
// 也可以查看 .ViewData 和 .ViewLayout。
// 示例:https://github.com/kataras/iris/tree/master/_examples/view/
View(filename string) error

// Binary 將原生字節作為二進制數據返回。
Binary(data []byte) (int, error)
// Text 將字符串作為空白文本返回。
Text(text string) (int, error)
// HTML 將字符串作為 text/html 返回.
HTML(htmlContents string) (int, error)
// JSON 格式化給定的數據並且返回 json 數據。
JSON(v interface{}, options ...JSON) (int, error)
// JSONP 格式化給定的數據並且返回 json 數據。
JSONP(v interface{}, options ...JSONP) (int, error)
// XML 格式話給定數據,並返回 XML 數據。
XML(v interface{}, options ...XML) (int, error)
// Markdown 解析 markdown 數據為 HTML 返回給客戶端。
Markdown(markdownB []byte, options ...Markdown) (int, error)

// +------------------------------------------------------------+
// | 文件響應 |
// +------------------------------------------------------------+

// ServeContent 返回的內容頭是自動設置的,接受三個參數,它是一個低級的函數,你可以調用 .ServeFile(string,bool)/SendFile(string,string)。
// 這個函數調用之后,你可以定義自己的 "Content-Type" 頭,不要實現 resuming,而應該使用 ctx.SendFile。
ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error
// ServeFile 渲染一個視圖文件,如果要發送一個文件(例如zip文件)到客戶端,你應該使用 SendFile(serverfilename,clientfilename)。
// 接受兩個參數:
// filename/path (string)
// gzipCompression (bool)
// 這個函數調用之后,你可以定義自己的 "Content-Type" 頭,這個函數沒有實現 resuming,你應該使用 ctx.SendFile。
ServeFile(filename string, gzipCompression bool) error
// SendFile 發送強制下載的文件到客戶端
//
// 使用這個而不是 ServeFile 用於大文件下載到客戶端。
SendFile(filename string, destinationName string) error

// +------------------------------------------------------------+
// | Cookies |
// +------------------------------------------------------------+

// SetCookie 添加cookie
SetCookie(cookie *http.Cookie)
// SetCookieKV 添加一個 cookie,僅僅接受一個名字(字符串)和一個值(字符串)
//
// 如果你用這個方法設置cookie,它將在兩小時之后失效。
// 如果你想去設置或者改變更多字段,使用 ctx.SetCookie 或者 http.SetCookie。
SetCookieKV(name, value string)
// GetCookie 通過名稱返回值,如果沒找到返回空字符串。
GetCookie(name string) string
// RemoveCookie 通過名字刪除 cookie。
RemoveCookie(name string)
// VisitAllCookies 接受一個 visitor 循環每個cookie,visitor 接受兩個參數:名稱和值。
VisitAllCookies(visitor func(name string, value string))

// MaxAge 返回 "cache-control" 請求頭的值,單位為:秒,類型為 int64
// 如果頭沒有發現或者解析失敗返回 -1。
MaxAge() int64

// +------------------------------------------------------------+
// | 高級部分: 響應記錄器和事務 |
// +------------------------------------------------------------+

// Record 轉化上下文基本的 responseWriter 為 ResponseRecorder,它可以被用於在任何時候重置內容體,
// 重置響應頭,獲取內容體,獲取和設置狀態碼。
Record()
// Recorder 返回上下文的 ResponseRecorder,如果沒有 recording 然后它將開始記錄並返回新的上下文的 ResponseRecorder。
Recorder() *ResponseRecorder
// IsRecording 返回響應記錄器以及一個bool值
// true 表示響應記錄器正在記錄狀態碼,內容體,HTTP 頭以及更多,否則就是 false
IsRecording() (*ResponseRecorder, bool)

// BeginTransaction 開啟一個有界事務。
//
// 你可以搜索第三方文章或者查看事務 Transaction 如何工作(這里相當簡單特別)。
//
// 記着這個是唯一的,也是新的,目前為止,我沒有在這個項目中看到任何例子和代碼,就大多數 iris 功能而言。
// 它沒有覆蓋所有路徑,例如數據庫,這個應該由你使用的創建數據庫連接的庫管理,這個事務域僅僅用於上下文響應,
//
// 閱讀 https://github.com/kataras/iris/tree/master/_examples/ 查看更多。
BeginTransaction(pipe func(t *Transaction))
// 如果調用 SkipTransactions 將跳過剩余的事務,或者如果在第一個事務之前調用,將跳過所有
SkipTransactions()
// TransactionsSkipped 返回事務到底被跳過還是被取消了。
TransactionsSkipped() bool

// Exec根據這個上下文調用framewrok的ServeCtx,但是改變了方法和路徑,就像用戶請求的那樣,但事實並非如此。
//
// 離線意味着路線已注冊到 iris 並具有正常路由所具有的所有功能。
// 但是它不能通過瀏覽獲得,它的處理程序僅在其他處理程序的上下文調用它們時執行,它可以驗證路徑,擁有會話,路徑參數等。
//
// 你可以通過 app.GetRoute("theRouteName") 找到路由,你可以設置一個路由名稱如:
// myRoute := app.Get("/mypath", handler)("theRouteName")
// 這個將給路由設置一個名稱並且返回它的 RouteInfo 實例為了進一步使用。
//
// 它不會更改全局狀態,如果路由處於“脫機”狀態,它將保持脫機狀態。
//
// app.None(...) and app.GetRoutes().Offline(route)/.Online(route, method)
//
// 實例:https://github.com/kataras/iris/tree/master/_examples/routing/route-state
//
// 用戶可以通過簡單調用得到響應:rec := ctx.Recorder(); rec.Body()/rec.StatusCode()/rec.Header()
//
// Context 的 Values 和 Session 被記住為了能夠通過結果路由通信,
//
// 它僅僅由於特別案例,99% 的用戶不會用到的。
Exec(method string, path string)

// Application 返回 屬於這個上下文的 iris 實例。
// 值得留意的是這個函數返回 Application 的一個接口,它包含的方法能夠安全地在運行是執行。
// 為了開發者的安全性,整個 app 的 字段和方法這里是不可用的。
Application() Application


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM