如何在Revel控制器中获取http.ResponseWriter和http.Request

时间:2019-03-08 19:25:17

标签: go revel

我正在尝试实现oauth服务器,并且我使用的软件包需要完整的http.ResponseWriter和http.Request类型。

c.Response不包含http.ResponseWriter包含的所有方法,并且c.Request提供错误不兼容的类型。

如何在Revel控制器中获取http.ResponseWriter和http.Request?

type client struct {
    ClientId string
    ClientSecret string
}
type App struct {
    *revel.Controller
}

func (c App) TokenRequest() {

    r := c.Request
    w := c.Response

    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        panic(err)
    }
    log.Println(string(body))

    var cli client
    err = json.Unmarshal(body, &cli)

    if err != nil {
        panic(err)
    }
    log.Println(cli.ClientId)

    err = OauthSrv.HandleTokenRequest(w, r)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

1 个答案:

答案 0 :(得分:0)

警告

由于我希望在此页面上展示自己的原因,所以我通常不喜欢Revel这样的框架。我的第一个建议是,您仔细检查一下您真正从Revel中学到的东西,这些东西值得使用如此沉重的抽象层,并且如果它真的那么有价值,那么您可能想问另一个方向的问题,例如如何可能会使OauthSrv在Revel的自定义生态系统中发挥作用。

使用Revel控制器作为ResponseWriter

要成为http.ResponseWriter,它只需具有these methods

标题

您需要一个名为Header()的方法,该方法返回一个http.Header,您可以在任何map[string][]string的基础上构建该方法。 Revel提供了类似的功能,但是要经过多个抽象层。您将需要解开它们:

  1. c.Response*Response,因此它有一个名为Out的字段,其中包含OutResponse
  2. OutResponse有一个Header()方法,但是它没有返回http.Header。而是返回一个*RevelHeader
  3. *RevelHeader有一个GetAll(key string) []string方法-与内置map类型已经提供的API非常相似,但并不完全相同。因此,您将需要在每次调用Header()时将返回的值复制到一个新的映射中,以便完全满足功能签名的要求。
  4. 此外,GetAll()要求您知道您感兴趣的密钥名称,而*RevelHeader本身并不能提供查找可用密钥的方法。 目前,我们可以依靠以下事实:the current implementation只有一个字段,确实提供了一种ServerHeader方法的GetKeys() []string

将所有这些放在一起,我们可以构建Header方法:

func (rrw RevelResponseWrapper) Header() http.Header {
  revelHeader := rrw.Response.Out.Header()
  keys := revelHeader.Server.GetKeys()
  headerMap := make(map[string][]string)

  for _, key := range keys {
    headerMap[key] = revelHeader.GetAll(key)
  }
  return http.Header(headerMap)
}

写入并写入标题

您将使用类似的反模式来公开rrw.Write([]byte) (int, error),以便调用到c.Response.Out.Write(data []byte) (int, error)rrw.WriteHeader(int) error,以便调用c.Response.WriteHeader(int, string)。取决于认为适合该框架的内容,是对错误感到恐慌还是无声失败,因为它们的API并不希望WriteHeader错误是可以处理的。

从Revel获取http.Request

不幸的是,http.Request类型是一个结构,因此您不能仅仅模拟它。您基本上有两个选择:使用net/http包从您可以访问的所有属性中对其进行重构,或者希望您拥有的*revel.Request暗地里是一个http.Request。在后一种情况下,您可以使用类型断言:

revelReq, ok := c.Request.In.(*revel.GoRequest)
if !ok {
  // handle this somehow
}
r := revelReq.Original