404 page not found after deploying Go server on heroku and render - go

After deploying my app to Heroku, all I get is a 404 - Page Not Found error. On my local machine it works just fine.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
)
type helloHngResponse struct{
SlackUsername string `json:"SlackUsername"`
Backend bool `json:"Backend"`
Age int `json:"Age"`
Bio string `json:"Bio"`
}
func helloHng(w http.ResponseWriter, r *http.Request){
response := helloHngResponse{SlackUsername: "kodeforce98", Backend: true, Age: 24, Bio: "Proud firstborn, Golang Developer, Committed christian, Faithful boyfriend"}
encoder := json.NewEncoder(w)
encoder.Encode(response)
}
I feel like the culprit is around here, but i'm lost still.
func main(){
port := os.Getenv("PORT")
if port == ""{
port = "9090"
}
http.HandleFunc("/hellohng", helloHng)
log.Printf("Server starting on port %v\n", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
}
i'm trying to understand why i'm not getting a json output as i do when i run it locally. every help's appreciated

Some guesses:
you might not have deployed at all - do you follow the deployment guide here: https://devcenter.heroku.com/articles/getting-started-with-go?singlepage=true ? If so, do you see the 404 in the server log?
you send request without port - do you send the request to the correct port? https://polar-inlet-4930.herokuapp.com:9000/hellohng. You may also change the port to 80 from 9000 in the code, which might help as 80 is default for web requests.

Related

https load balancer with fiber is not working

I am trying to make simple load balancer using fiber in Go. In my computer it's working fine using http.
import (
"crypto/tls"
"log"
"os"
store "intraGo/stores/session_store"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/proxy"
"github.com/gofiber/template/html"
)
...
if os.Getenv("CERT_FILE") == "" || os.Getenv("KEY_FILE") == "" {
// this part is working fine
app.Use(proxy.Balancer(proxy.Config{Servers: []string{"http://localhost:9000"}}))
log.Fatal(app.Listen(":" + os.Getenv("SERVER_PORT")))
} else {
app.Use(proxy.Balancer(proxy.Config{Servers: []string{"https://servername.com"}}))
cer, err := tls.LoadX509KeyPair(os.Getenv("CERT_FILE"), os.Getenv("KEY_FILE"))
if err != nil {
log.Fatal(err)
}
config := &tls.Config{Certificates: []tls.Certificate{cer}}
ln, err := tls.Listen("tcp", ":"+os.Getenv("SERVER_PORT"), config)
if err != nil {
panic(err)
}
log.Fatal(app.Listener(ln))
}
In the production envirment using https it will give me a http 500 result with the follwing text for every request. The request will never reach the server.
HostClient can't follow redirects to a different protocol, please use Client instead
I checked Go / fiber documentation but did not find anything that could help to solve this issue. I also checked if the https part (like certificates, https server) is working fine by adding this to my app:
app.get("/", (req, res) => { res.send("Hello World!"); });
This worked as expected, so I guess the problem is in the loadbalancer itself.
Found this link while trying to find the solution on the net, I am not sure, but this might be related to the problem:
https://github.com/valyala/fasthttp/issues/841

Why Google Logging client libraries not logging inside Google cloud functions?

I'm trying to implement a google cloud function to test Google Logging client library. below is my code
// Package p contains an HTTP Cloud Function.
package loggingclient
import (
"cloud.google.com/go/logging"
"net/http"
"context"
"fmt"
)
// HelloWorld prints the JSON encoded "message" field in the body
// of the request or "Hello, World!" if there isn't one.
func HelloWorld(w http.ResponseWriter, r *http.Request) {
label := map[string]string{"priority": "High"}
var projectName = "my-project-id"
ctx := context.Background()
client, err := logging.NewClient(ctx, projectName)
if err != nil {
fmt.Printf("client not created: %v", err)
}
lg := client.Logger("MY-LOGGER")
lg.Log(logging.Entry{
Payload: "Hello, This is error!!",
Severity: logging.Error,
Labels: label,
})
client.Close()
}
Here, I'm expecting a log entry with a message:"Hello, This is error!!" and with a lable:"priority": "High" and severirty "ERROR"
But actually, when I trigger this Cloud Function, I didn't get any new log entries. Therefore don't client logging libraries work inside cloud functions?, How to resolve this?
Thanks
It works on cloud functions. I have done the exact same thing in a cloud function before. You can use google's official documenation with cloud function logging here
Also ensure that the service account have necessary permissions for logging
https://cloud.google.com/logging/docs/access-control

Heroku Go app is no longer working after a few minutes

I had trouble getting my React app to run on GitHub pages, so I chose to try and serve the files on my Go backend which is on Heroku. At first I was serving the React app through the main Go backend, which did serve the React app successfully but none of my other routes would work after that in the Go app, the routes needed for my React app to operate.
So I chose to create a new Heroku Go app and separate the backend and frontend on different Heroku Go apps. The frontend Go app is running fine, but the backend will intermittently work. I understand Heroku free apps go into a sleep state with a period of inactivity, but I am literally talking about the app being online for a few minutes, and then all of sudden just switching back to the default mode of saying "no such app"
Frontend Heroku Go app:
// Route: Delete Graph from database
func RouteDefault(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
http.ServeFile(w, r, "static/index.html")
}
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "9000" // Default port if not specified
}
// HTTPRouter Settings and Routes
router := httprouter.New()
router.GET("/", RouteDefault)
// if not found look for a static file
static := httprouter.New()
static.ServeFiles("/*filepath", http.Dir("static"))
router.NotFound = static
handler := cors.AllowAll().Handler(router)
fmt.Println(http.ListenAndServe(":"+port, handler))
}
Backend Heroku Go app:
func main() {
// BasicAuth username and password
user := ""
pass := ""
port := os.Getenv("PORT")
if port == "" {
port = "9000" // Default port if not specified
}
DefaultUser()
// HTTPRouter Settings and Routes
router := httprouter.New()
router.POST("/login/", BasicAuth(RouteLogin, user, pass))
router.POST("/upload/", JWTAuth(RouteUpload))
router.POST("/graph/", JWTAuth(RouteGetGraph))
router.GET("/autologin/", JWTAuth(RouteAutoLogin))
handler := cors.AllowAll().Handler(router)
fmt.Println(http.ListenAndServe(":"+port, handler))
}
Frontend: https://grafulatordemo.herokuapp.com/
Backend: https://grafulator.herokuapp.com/
run the command: heroku apps -A and share the relevant output so it can be troubleshooted
The problem was on heroku's end, contacting their support team resolved it.

How to get full server URL from any endpoint handler in Gin

I'm creating an endpoint using Go's Gin web framework. I need full server URL in my handler function. For example, if server is running on http://localhost:8080 and my endpoint is /foo then I need http://localhost:8080/foo when my handler is called.
If anyone is familiar with Python's fast API, the Request object has a method url_for(<endpoint_name>) which has the exact same functionality: https://stackoverflow.com/a/63682957/5353128
In Go, I've tried accessing context.FullPath() but that only returns my endpoint /foo and not the full URL. Other than this, I can't find appropriate method in docs: https://pkg.go.dev/github.com/gin-gonic/gin#Context
So is this possible via gin.Context object itself or are there other ways as well? I'm completely new to Go.
c.Request.Host+c.Request.URL.Path should work but the scheme has to be determined.
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/foo", func(c *gin.Context) {
fmt.Println("The URL: ", c.Request.Host+c.Request.URL.Path)
})
r.Run(":8080")
}
You can determine scheme which also you may know already. But you can check as follows:
scheme := "http"
if c.Request.TLS != nil {
scheme = "https"
}
If your server is behind the proxy, you can get the scheme by c.Request.Header.Get("X-Forwarded-Proto")
You can get host part localhost:8080 from context.Request.Host and path part /foo from context.Request.URL.String().
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/foo", func(c *gin.Context) {
c.String(http.StatusOK, "bar")
fmt.Println(c.Request.Host+c.Request.URL.String())
})
// Listen and Server in 0.0.0.0:8080
r.Run(":8080")
}
And you can get http protocol version by context.Request.Proto, But it will not determine http or https. you need to get it from your service specifications.

How to Make My Web Server written in Golang to support HTTP/2 Server Push?

My Web Server is Coded in Golang and supports HTTPS. I wish to leverage HTTP/2 Server Push features in the Web Server. The following Link explains how to convert HTTP Server to Support HTTP/2 :-
https://www.ianlewis.org/en/http2-and-go
However, it is not clear how to implement the Server Push notifications in Golang.
- How should I add the Server Push functionality ?
- How do I control, or manage, the documents and files to be Pushed ?
Go 1.7 and older do not support HTTP/2 server push in the standard library. Support for server push will be added in the upcoming 1.8 release (see the release notes, expected release is February).
With Go 1.8 you can use the new http.Pusher interface, which is implemented by net/http's default ResponseWriter. Pushers Push method returns ErrNotSupported, if server push is not supported (HTTP/1) or not allowed (the client has disabled server push).
Example:
package main
import (
"io"
"log"
"net/http"
)
func main() {
http.HandleFunc("/pushed", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello server push")
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if pusher, ok := w.(http.Pusher); ok {
if err := pusher.Push("/pushed", nil); err != nil {
log.Println("push failed")
}
}
io.WriteString(w, "hello world")
})
http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
}
If you want to use server push with Go 1.7 or older use can use the golang.org/x/net/http2 and write the frames directly.
As mentioned in other answers, you can make use of Go 1.8 feature (cast the writer to http.Pusher and then use the Push method).
That comes with a caveat: you must be serving the HTTP2 traffic right from your server.
If you're behind a proxy like NGINX, this might not work. If you want to consider that scenario, you can make use of the Link header to advertise the URLs to be pushed.
// In the case of HTTP1.1 we make use of the `Link` header
// to indicate that the client (in our case, NGINX) should
// retrieve a certain URL.
//
// See more at https://www.w3.org/TR/preload/#server-push-http-2.
func handleIndex(w http.ResponseWriter, r *http.Request) {
var err error
if *http2 {
pusher, ok := w.(http.Pusher)
if ok {
must(pusher.Push("/image.svg", nil))
}
} else {
// This ends up taking the effect of a server push
// when interacting directly with NGINX.
w.Header().Add("Link",
"</image.svg>; rel=preload; as=image")
}
w.Header().Add("Content-Type", "text/html")
_, err = w.Write(assets.Index)
must(err)
}
ps.: I wrote more about this here https://ops.tips/blog/nginx-http2-server-push/ if you're interested.

Resources