# 核心服务

Macaron 会注入一些默认服务来驱动您的应用，这些服务被称之为 **核心服务**。也就是说，您可以直接使用它们作为处理器参数而不需要任何附加工作。

## 请求上下文（Context）

该服务通过类型 [`*macaron.Context`](https://gowalker.org/gopkg.in/macaron.v1#Context) 来体现。这是 Macaron 最为核心的服务，您的任何操作都是基于它之上。该服务包含了您所需要的请求对象、响应流、模板引擎接口、数据存储和注入与获取其它服务。

使用方法：

```go
package main

import "gopkg.in/macaron.v1"

func Home(ctx *macaron.Context) {
    // ...
}
```

### Next()

方法 [`Context.Next`](https://gowalker.org/gopkg.in/macaron.v1#Context_Next) 是一个可选的功能，它可以用于中间件处理器暂时放弃执行，等待其他的处理器都执行完毕后继续执行。这样就可以很好的处理在 HTTP 请求完成后需要做的操作：

```go
// log before and after a request
m.Use(func(ctx *macaron.Context, log *log.Logger){
    log.Println("before a request")

    ctx.Next()

    log.Println("after a request")
})
```

### Cookie

最基本的 Cookie 用法：

* [`*macaron.Context.SetCookie`](https://gowalker.org/gopkg.in/macaron.v1#Context_SetCookie)
* [`*macaron.Context.GetCookie`](https://gowalker.org/gopkg.in/macaron.v1#Context_GetCookie)、[`*macaron.Context.GetCookieInt`](https://gowalker.org/gopkg.in/macaron.v1#Context_GetCookieInt)、[`*macaron.Context.GetCookieInt64`](https://gowalker.org/gopkg.in/macaron.v1#Context_GetCookieInt64)、[`*macaron.Context.GetCookieFloat64`](https://gowalker.org/gopkg.in/macaron.v1#Context_GetCookieFloat64)

使用方法：

```go
// ...
m.Get("/set", func(ctx *macaron.Context) {
    ctx.SetCookie("user", "Unknwon", 1)
})

m.Get("/get", func(ctx *macaron.Context) string {
    return ctx.GetCookie("user")
})
// ...
```

使用以下顺序的参数来设置更多的属性：`SetCookie(<name>, <value>, <max age>, <path>, <domain>, <secure>, <http only>)`。

因此，设置 Cookie 最完整的用法为：`SetCookie("user", "unknwon", 999, "/", "localhost", true, true)`。

需要注意的是，参数的顺序是固定的。

如果需要更加安全的 Cookie 机制，可以先使用 [`macaron.SetDefaultCookieSecret`](https://gowalker.org/gopkg.in/macaron.v1#Macaron_SetDefaultCookieSecret) 设定密钥，然后使用：

* [`*macaron.Context.SetSecureCookie`](https://gowalker.org/gopkg.in/macaron.v1#Context_SetSecureCookie)
* [`*macaron.Context.GetSecureCookie`](https://gowalker.org/gopkg.in/macaron.v1#Context_GetSecureCookie)

这两个方法将会自动使用您设置的默认密钥进行加密/解密 Cookie 值。

使用方法：

```go
// ...
m.SetDefaultCookieSecret("macaron")
m.Get("/set", func(ctx *macaron.Context) {
    ctx.SetSecureCookie("user", "Unknwon", 1)
})

m.Get("/get", func(ctx *macaron.Context) string {
    name, _ := ctx.GetSecureCookie("user")
    return name
})
// ...
```

对于那些对安全性要求特别高的应用，可以为每次设置 Cookie 使用不同的密钥加密/解密：

* [`*macaron.Context.SetSuperSecureCookie`](https://gowalker.org/gopkg.in/macaron.v1#Context_SetSuperSecureCookie)
* [`*macaron.Context.GetSuperSecureCookie`](https://gowalker.org/gopkg.in/macaron.v1#Context_GetSuperSecureCookie)

使用方法：

```go
// ...
m.Get("/set", func(ctx *macaron.Context) {
    ctx.SetSuperSecureCookie("macaron", "user", "Unknwon", 1)
})

m.Get("/get", func(ctx *macaron.Context) string {
    name, _ := ctx.GetSuperSecureCookie("macaron", "user")
    return name
})
// ...
```

### 其它辅助方法

* 设置/获取 URL 参数：[`ctx.SetParams`](https://gowalker.org/gopkg.in/macaron.v1#Context_SetParams) / [`ctx.Params`](https://gowalker.org/gopkg.in/macaron.v1#Context_Params)、[`ctx.ParamsEscape`](https://gowalker.org/gopkg.in/macaron.v1#Context_ParamsEscape)、[`ctx.ParamsInt`](https://gowalker.org/gopkg.in/macaron.v1#Context_ParamsInt)、[`ctx.ParamsInt64`](https://gowalker.org/gopkg.in/macaron.v1#Context_ParamsInt64)、[`ctx.ParamsFloat64`](https://gowalker.org/gopkg.in/macaron.v1#Context_ParamsFloat64)
* 获取查询参数：[`ctx.Query`](https://gowalker.org/gopkg.in/macaron.v1#Context_ctx.Query)、[`ctx.QueryEscape`](https://gowalker.org/gopkg.in/macaron.v1#Context_ctx.QueryEscape)、[`ctx.QueryInt`](https://gowalker.org/gopkg.in/macaron.v1#Context_ctx.QueryInt)、[`ctx.QueryInt64`](https://gowalker.org/gopkg.in/macaron.v1#Context_ctx.QueryInt64)、[`ctx.QueryFloat64`](https://gowalker.org/gopkg.in/macaron.v1#Context_ctx.QueryFloat64)、[`ctx.QueryStrings`](https://gowalker.org/gopkg.in/macaron.v1#Context_ctx.QueryStrings)、[`ctx.QueryTrim`](https://gowalker.org/gopkg.in/macaron.v1#Context_QueryTrim)
* 服务内容或文件：[`ctx.ServeContent`](https://gowalker.org/gopkg.in/macaron.v1#Context_ServeContent)、[`ctx.ServeFile`](https://gowalker.org/gopkg.in/macaron.v1#Context_ServeFile)、[`ctx.ServeFile`](https://gowalker.org/gopkg.in/macaron.v1#Context_ServeFile), [`ctx.ServeFileContent`](https://gowalker.org/gopkg.in/macaron.v1#Context_ServeFileContent)
* 获取远程 IP 地址：[`ctx.RemoteAddr`](https://gowalker.org/gopkg.in/macaron.v1#Context_RemoteAddr)

## 路由日志

该服务可以通过函数 [`macaron.Logger`](https://gowalker.org/gopkg.in/macaron.v1#Logger) 来注入。该服务主要负责应用的路由日志。

使用方法：

```go
package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.New()
    m.Use(macaron.Logger())
    // ...
}
```

{% hint style="info" %}
当您使用 [`macaron.Classic`](https://gowalker.org/gopkg.in/macaron.v1#Classic) 时，该服务会被自动注入。
{% endhint %}

从 [Peach Docs](https://github.com/peachdocs/peach) 项目中提取的样例输出：

```
[Macaron] Started GET /docs/middlewares/core.html for [::1]
[Macaron] Completed /docs/middlewares/core.html 200 OK in 2.114956ms
```

## 容错恢复

该服务可以通过函数 [`macaron.Recovery`](https://gowalker.org/gopkg.in/macaron.v1#Recovery) 来注入。该服务主要负责在应用发生恐慌（panic）时进行恢复。

使用方法：

```go
package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.New()
    m.Use(macaron.Recovery())
    // ...
}
```

{% hint style="info" %}
当您使用 [`macaron.Classic`](https://gowalker.org/gopkg.in/macaron.v1#Classic) 时，该服务会被自动注入。
{% endhint %}

## 静态文件

该服务可以通过函数 [`macaron.Static`](https://gowalker.org/gopkg.in/macaron.v1#Static) 来注入。该服务主要负责应用静态资源的服务，当您的应用拥有多个静态目录时，可以对其进行多次注入。

使用方法：

```go
package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.New()
    m.Use(macaron.Static("public"))
    m.Use(macaron.Static("assets"))
    // ...
}
```

{% hint style="info" %}
当您使用 [`macaron.Classic`](https://gowalker.org/gopkg.in/macaron.v1#Classic) 时，该服务会以 `public` 为静态目录被自动注入。
{% endhint %}

默认情况下，当您请求一个目录时，该服务不会列出目录下的文件，而是去寻找 `index.html` 文件。

从 [Peach](https://github.com/peachdocs/peach) 项目中提取的样例输出：

```
[Macaron] Started GET /css/prettify.css for [::1]
[Macaron] [Static] Serving /css/prettify.css
[Macaron] Completed /css/prettify.css 304 Not Modified in 97.584us
[Macaron] Started GET /imgs/macaron.png for [::1]
[Macaron] [Static] Serving /imgs/macaron.png
[Macaron] Completed /imgs/macaron.png 304 Not Modified in 123.211us
[Macaron] Started GET /js/gogsweb.min.js for [::1]
[Macaron] [Static] Serving /js/gogsweb.min.js
[Macaron] Completed /js/gogsweb.min.js 304 Not Modified in 47.653us
[Macaron] Started GET /css/main.css for [::1]
[Macaron] [Static] Serving /css/main.css
[Macaron] Completed /css/main.css 304 Not Modified in 42.58us
```

### 使用示例

假设您的应用拥有以下目录结构：

```
public/
    |__ html
            |__ index.html
    |__ css/
            |__ main.css
```

响应结果：

| 请求 URL            | 匹配文件       |
| ----------------- | ---------- |
| `/html/main.html` | 匹配失败       |
| `/html/`          | index.html |
| `/css/main.css`   | main.css   |

### 自定义选项

该服务允许接受第二个参数来进行自定义选项操作（[`macaron.StaticOptions`](https://gowalker.org/gopkg.in/macaron.v1#StaticOptions)）：

```go
package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.New()
    m.Use(macaron.Static("public",
        macaron.StaticOptions{
            // 请求静态资源时的 URL 前缀，默认没有前缀
            Prefix: "public",
            // 禁止记录静态资源路由日志，默认为不禁止记录
            SkipLogging: true,
            // 当请求目录时的默认索引文件，默认为 "index.html"
            IndexFile: "index.html",
            // 用于返回自定义过期响应头，默认为不设置
            // https://developers.google.com/speed/docs/insights/LeverageBrowserCaching
            Expires: func() string { 
                return time.Now().Add(24 * 60 * time.Minute).UTC().Format("Mon, 02 Jan 2006 15:04:05 GMT")
            },
        }))
    // ...
}
```

### 注册多个静态处理器

如果您需要一次注册多个静态处理器，可以使用方法 [`macaron.Statics`](https://gowalker.org/gopkg.in/macaron.v1#Statics) 来简化您的工作。

使用方法：

```go
// ...
m.Use(macaron.Statics(macaron.StaticOptions{}, "public", "views"))
// ...
```

这样，就可以同时注册 `public` 和 `views` 为静态目录了。

## 其它服务

### 全局日志

该服务通过类型 [`*log.Logger`](http://gowalker.org/log#Logger) 来体现。该服务为可选，只是为没有日志器的应用提供一定的便利。

使用方法：

```go
package main

import (
    "log"

    "gopkg.in/macaron.v1"
)

func main() {
    m := macaron.Classic()
    m.Get("/", myHandler)
    m.Run()
}

func myHandler(ctx *macaron.Context, logger *log.Logger) string {
    logger.Println("the request path is: " + ctx.Req.RequestURI)
    return "the request path is: " + ctx.Req.RequestURI
}
```

{% hint style="info" %}
所有 [Macaron 实例](/zh-cn/core_concepts.md#macaron-shi-li) 都会自动注册该服务。
{% endhint %}

### 响应流

该服务通过类型 [`http.ResponseWriter`](http://gowalker.org/net/http#ResponseWriter) 来体现。该服务为可选，一般情况下可直接使用 `*macaron.Context.Resp`。

使用方法：

```go
package main

import (
    "gopkg.in/macaron.v1"
)

func main() {
    m := macaron.Classic()
    m.Get("/", myHandler)
    m.Run()
}

func myHandler(ctx *macaron.Context) {
    ctx.Resp.Write([]byte("the request path is: " + ctx.Req.RequestURI))
}
```

{% hint style="info" %}
所有 [Macaron 实例](/zh-cn/core_concepts.md#macaron-shi-li) 都会自动注册该服务。
{% endhint %}

### 请求对象

该服务通过类型 [`*http.Request`](http://gowalker.org/net/http#Request) 来体现。该服务为可选，一般情况下可直接使用 `*macaron.Context.Req`。

除此之外，该服务还提供了 3 个便利的方法来获取请求体：

* [`*macaron.Context.Req.Body().String()`](https://gowalker.org/gopkg.in/macaron.v1#RequestBody_String)：获取 `string` 类型的请求体
* [`*macaron.Context.Req.Body().Bytes()`](https://gowalker.org/gopkg.in/macaron.v1#RequestBody_Bytes)：获取 `[]byte` 类型的请求体
* [`*macaron.Context.Req.Body().ReadCloser()`](https://gowalker.org/gopkg.in/macaron.v1#RequestBody_ReadCloser)：获取 `io.ReadCloser` 类型的请求体

使用方法：

```go
package main

import (
    "gopkg.in/macaron.v1"
)

func main() {
    m := macaron.Classic()
    m.Get("/body1", func(ctx *macaron.Context) {
        reader, err := ctx.Req.Body().ReadCloser()
        // ...
    })
    m.Get("/body2", func(ctx *macaron.Context) {
        data, err := ctx.Req.Body().Bytes()
        // ...
    })
    m.Get("/body3", func(ctx *macaron.Context) {
        data, err := ctx.Req.Body().String()
        // ...
    })
    m.Run()
}
```

需要注意的是，请求体在每个请求中只能被读取一次。

有时您需要传递类型为 [`*http.Request`](http://gowalker.org/net/http#Request) 的参数，则应该使用 `*macaron.Context.Req.Request`。

{% hint style="info" %}
所有 [Macaron 实例](/zh-cn/core_concepts.md#macaron-shi-li) 都会自动注册该服务。
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://go-macaron.com/zh-cn/core_services.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
