Предупреждение
Мне вообще не нравятся фреймворки, такие как Revel in Go, по причинам, которые я надеюсь продемонстрировать на этой странице.Моей первой рекомендацией было бы внимательно изучить, что вы на самом деле получаете от Revel, что заслуживает использования такого тяжелого уровня абстракции, и если это действительно так ценно, вы можете задавать вопросы в другом направлении, например, какможно заставить OauthSrv
работать в настроенной экосистеме Revel.
Использование контроллера Revel в качестве ResponseWriter
Чтобы что-то было http.ResponseWriter
, ему просто нужно иметь эти методы.
Заголовок
Вам необходим метод с именем Header()
, который возвращает http.Header
, который вы можете построить из любого map[string][]string
.Revel предоставляет аналогичную функциональность, но через несколько уровней абстракции.Вам нужно будет их распутать:
c.Response
- это *Response
, поэтому в нем есть поле с именем Out
, содержащее OutResponse
. - An
OutResponse
имеет метод Header()
, но он не возвращает http.Header
.Вместо этого он возвращает *RevelHeader
. - A
*RevelHeader
имеет метод GetAll(key string) []string
, который очень похож на API, уже предоставленный встроенным типом map
, но не совсемтот же самый.Таким образом, вам нужно будет копировать возвращаемые значения в новую карту каждый раз, когда вызывается Header()
, чтобы полностью удовлетворить требования сигнатуры функции. - Кроме того,
GetAll()
требует, чтобы вы знали имя ключаВы заинтересованы в этом, и *RevelHeader
сам по себе не позволяет найти доступные ключи. На данный момент мы можем полагаться на тот факт, что текущая реализация имеет только одно поле, а 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)
}
Write и WriteHeader
Вы бы использовали аналогичные анти-паттерны, чтобы выставить rrw.Write([]byte) (int, error)
чтобы он звонил на c.Response.Out.Write(data []byte) (int, error)
и rrw.WriteHeader(int) error
, чтобы он звонил c.Response.WriteHeader(int, string)
.В зависимости от того, что считается подходящим для платформы, либо паникуйте по ошибкам, либо молча терпите неудачу, так как их API не ожидает, что WriteHeader
ошибки будут обработаны.
Получение http.Request от Revel
К сожалению, тип http.Request
является структурой, поэтому вы не можете просто смоделировать его.По сути, у вас есть два варианта: восстановить его с помощью пакета net/http
из всех свойств, к которым у вас есть доступ, или надеяться, что *revel.Request
, который у вас есть, тайно http.Request
под капотом.В последнем случае вы можете использовать утверждение типа:
revelReq, ok := c.Request.In.(*revel.GoRequest)
if !ok {
// handle this somehow
}
r := revelReq.Original