Messing about with a small project: it's basically a reverse proxy
that will convert json responses from the origin server to lovely html
in the client request. It decodes the json response from the origin
and passes this struct to the mustache templating engine which outputs
html.
The server has a config file allowing the user to specify url patterns
to match and destination urls to proxy to:
{
"pattern":"/hello",
"origin":"http://example.com/some/destination",
"template":"./hello.template"
} // etc, etc
I'm having difficulty understanding our friend
httputil.NewSingleHostReverseProxy(). It may have something to do with
the way I have approached this though.
Ideally I have a http server. This assigns a handler for each entry in
the config file, matched by pattern. The handler creates a new proxy
server using httputil.NewSingleHostReverseProxy() with the origin
config parameter as the target argument. I then have a custom
http.RequestWriter that reads the json body in response, parses it,
passes it to mustache and writes the output:
type MustacheWriter struct {
Template []byte
w io.Writer
}
func (w MustacheWriter) Write(b []byte) (int, error) {
var f interface{}
err := json.Unmarshal(b, &f)
if err != nil {
log.Fatal(err, string(b))
}
m := f.(map[string]interface{})
d := mustache.Render(string(w.Template), m)
return w.Write([]byte(d))
}
The problem is that I keep getting "File not found" passed into the
Write(b []byte) argument, even though if I curl the URL being passed
as the origin I get valid JSON back.
So, questions!
1) Am I using NewSingleHostReverseProxy() correctly?
2) Is there a problem with my approach to this problem?
3) Is there a better way?
omarshariffdontlik...@gmail.com> wrote:
> Hi Gophers!
> Messing about with a small project: it's basically a reverse proxy
> that will convert json responses from the origin server to lovely html
> in the client request. It decodes the json response from the origin
> and passes this struct to the mustache templating engine which outputs
> html.
> The server has a config file allowing the user to specify url patterns
> to match and destination urls to proxy to:
> {
> "pattern":"/hello",
> "origin":"http://example.com/some/destination",
> "template":"./hello.template"
> } // etc, etc
> I'm having difficulty understanding our friend
> httputil.NewSingleHostReverseProxy(). It may have something to do with
> the way I have approached this though.
> Ideally I have a http server. This assigns a handler for each entry in
> the config file, matched by pattern. The handler creates a new proxy
> server using httputil.NewSingleHostReverseProxy() with the origin
> config parameter as the target argument. I then have a custom
> http.RequestWriter that reads the json body in response, parses it,
> passes it to mustache and writes the output:
> type MustacheWriter struct {
> Template []byte
> w io.Writer
> }
> func (w MustacheWriter) Write(b []byte) (int, error) {
> var f interface{}
> err := json.Unmarshal(b, &f)
> if err != nil {
> log.Fatal(err, string(b))
> }
> m := f.(map[string]interface{})
> d := mustache.Render(string(w.Template), m)
> return w.Write([]byte(d))
> }
> The problem is that I keep getting "File not found" passed into the
> Write(b []byte) argument, even though if I curl the URL being passed
> as the origin I get valid JSON back.
> So, questions!
> 1) Am I using NewSingleHostReverseProxy() correctly?
2) Is there a problem with my approach to this problem?
Ah, but a want a FULL HTTP proxy, passing though POSTs, GET, DELETE
etc;
Are you suggesting that NewSingleHostReverseProxy is not suitable for
this task? I may have misunderstood but I thought that this is exactly
what NewSingleHostReverseProxy is for.
On Apr 26, 6:50 pm, Kyle Lemons <kev...@google.com> wrote:
> On Thu, Apr 26, 2012 at 6:58 AM, OmarShariffDontLikeIt <
> omarshariffdontlik...@gmail.com> wrote:
> > Hi Gophers!
> > Messing about with a small project: it's basically a reverse proxy
> > that will convert json responses from the origin server to lovely html
> > in the client request. It decodes the json response from the origin
> > and passes this struct to the mustache templating engine which outputs
> > html.
> > The server has a config file allowing the user to specify url patterns
> > to match and destination urls to proxy to:
> > {
> > "pattern":"/hello",
> > "origin":"http://example.com/some/destination",
> > "template":"./hello.template"
> > } // etc, etc
> > I'm having difficulty understanding our friend
> > httputil.NewSingleHostReverseProxy(). It may have something to do with
> > the way I have approached this though.
> > Ideally I have a http server. This assigns a handler for each entry in
> > the config file, matched by pattern. The handler creates a new proxy
> > server using httputil.NewSingleHostReverseProxy() with the origin
> > config parameter as the target argument. I then have a custom
> > http.RequestWriter that reads the json body in response, parses it,
> > passes it to mustache and writes the output:
> The actual URL is created by combining r with url. Just do an http.Get on
> URL unless you actually want a reverse proxy for a directory or something.
> > }
> > }
> > And the mustache writer looky likey thisy:
> > type MustacheWriter struct {
> > Template []byte
> > w io.Writer
> > }
> > func (w MustacheWriter) Write(b []byte) (int, error) {
> > var f interface{}
> > err := json.Unmarshal(b, &f)
> > if err != nil {
> > log.Fatal(err, string(b))
> > }
> > m := f.(map[string]interface{})
> > d := mustache.Render(string(w.Template), m)
> > return w.Write([]byte(d))
> > }
> > The problem is that I keep getting "File not found" passed into the
> > Write(b []byte) argument, even though if I curl the URL being passed
> > as the origin I get valid JSON back.
> > So, questions!
> > 1) Am I using NewSingleHostReverseProxy() correctly?
> 2) Is there a problem with my approach to this problem?
You said that you can CURL the route URL, so I assumed that the route URL
was the one that was returning the JSON. The route URL is being modified
by ReverseProxy, so that CURL is not going to reproduce the behavior. I
believe you can wrap the default Director with your own and log the new
path if you want to see what it's doing.
On Thu, Apr 26, 2012 at 11:13 AM, OmarShariffDontLikeIt <
omarshariffdontlik...@gmail.com> wrote:
> Ah, but a want a FULL HTTP proxy, passing though POSTs, GET, DELETE
> etc;
> Are you suggesting that NewSingleHostReverseProxy is not suitable for
> this task? I may have misunderstood but I thought that this is exactly
> what NewSingleHostReverseProxy is for.
> On Apr 26, 6:50 pm, Kyle Lemons <kev...@google.com> wrote:
> > On Thu, Apr 26, 2012 at 6:58 AM, OmarShariffDontLikeIt <
> > omarshariffdontlik...@gmail.com> wrote:
> > > Hi Gophers!
> > > Messing about with a small project: it's basically a reverse proxy
> > > that will convert json responses from the origin server to lovely html
> > > in the client request. It decodes the json response from the origin
> > > and passes this struct to the mustache templating engine which outputs
> > > html.
> > > The server has a config file allowing the user to specify url patterns
> > > to match and destination urls to proxy to:
> > > {
> > > "pattern":"/hello",
> > > "origin":"http://example.com/some/destination",
> > > "template":"./hello.template"
> > > } // etc, etc
> > > I'm having difficulty understanding our friend
> > > httputil.NewSingleHostReverseProxy(). It may have something to do with
> > > the way I have approached this though.
> > > Ideally I have a http server. This assigns a handler for each entry in
> > > the config file, matched by pattern. The handler creates a new proxy
> > > server using httputil.NewSingleHostReverseProxy() with the origin
> > > config parameter as the target argument. I then have a custom
> > > http.RequestWriter that reads the json body in response, parses it,
> > > passes it to mustache and writes the output:
> > The actual URL is created by combining r with url. Just do an http.Get
> on
> > URL unless you actually want a reverse proxy for a directory or
> something.
> > > m := f.(map[string]interface{})
> > > d := mustache.Render(string(w.Template), m)
> > > return w.Write([]byte(d))
> > > }
> > > The problem is that I keep getting "File not found" passed into the
> > > Write(b []byte) argument, even though if I curl the URL being passed
> > > as the origin I get valid JSON back.
> > > So, questions!
> > > 1) Am I using NewSingleHostReverseProxy() correctly?
> > 2) Is there a problem with my approach to this problem?
> > The route URL is being modified by ReverseProxy
> Ah, interesting! Why does it do that!?
From the documentation: "NewSingleHostReverseProxy returns a new
ReverseProxy that rewrites URLs to the scheme, host, and base path provided
in target. If the target's path is "/base" and the incoming request was for
"/dir", the target request will be for /base/dir."
> > believe you can wrap the default Director with your own and log the new
> > path if you want to see what it's doing.
> Ooo that sounds just what I need to do to work out the problem. Could
> you give me an example of what you mean?
On Thursday, April 26, 2012 6:58:45 AM UTC-7, OmarShariffDontLikeIt wrote:
> Hi Gophers!
> Messing about with a small project: it's basically a reverse proxy > that will convert json responses from the origin server to lovely html > in the client request. It decodes the json response from the origin > and passes this struct to the mustache templating engine which outputs > html.
> The server has a config file allowing the user to specify url patterns > to match and destination urls to proxy to: > { > "pattern":"/hello", > "origin":"http://example.com/some/destination", > "template":"./hello.template" > } // etc, etc
> I'm having difficulty understanding our friend > httputil.NewSingleHostReverseProxy(). It may have something to do with > the way I have approached this though.
> Ideally I have a http server. This assigns a handler for each entry in > the config file, matched by pattern. The handler creates a new proxy > server using httputil.NewSingleHostReverseProxy() with the origin > config parameter as the target argument. I then have a custom > http.RequestWriter that reads the json body in response, parses it, > passes it to mustache and writes the output:
> type MustacheWriter struct { > Template []byte > w io.Writer > }
> func (w MustacheWriter) Write(b []byte) (int, error) { > var f interface{} > err := json.Unmarshal(b, &f) > if err != nil { > log.Fatal(err, string(b)) > }
> m := f.(map[string]interface{}) > d := mustache.Render(string(w.Template), m)
> return w.Write([]byte(d)) > }
> The problem is that I keep getting "File not found" passed into the > Write(b []byte) argument, even though if I curl the URL being passed > as the origin I get valid JSON back.
> So, questions!
> 1) Am I using NewSingleHostReverseProxy() correctly? > 2) Is there a problem with my approach to this problem? > 3) Is there a better way?
> You could have a look at falcore (github.com/ngmoco/falcore). One of the
> core things we built it for was reverse proxying into other applications.
Having a quick read, I must say I really do like the pipelining of
filters. It reminds me a lot of Apaches filters (without the fiddly
mess!).
After a brief look, I can't find anything relating to actually
proxying a request to a back end. Is this built in, a filter, or would
I have to write this myself?
Thanks for the heads up on Falcore, I takes an approach I am familiar
with (filters/pipeline) so I may end up switching my project over to
this approach as it would result in a much cleaner architecture,
especially as I have several features I would like to add in future
that would be trivial to add as additional filters.
> After a brief look, I can't find anything relating to actually
> proxying a request to a back end. Is this built in, a filter, or would
> I have to write this myself?
Just found it; the upstream dir contains a upstream/proxy filter.