Issuing HTTP Get Request in Flexible Environment in App Engine - http

I am using Flexible Environment in App engine I want to send HTTP Get request in my code.
ctx := appengine.NewContext(r)
client := urlfetch.Client(ctx)
req, err := http.NewRequest("GET", "https://www.google.com/", nil)
res, err := client.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "HTTP GET returned status %v", res.Status)
When I run app I get the following error:
https://www.google.com/: not an App Engine context
The above code works in Standard Environment and but it is not working in flexible environment.

You don't need URL Fetch in App Engine Flexible, you can simply issue the http request: https://cloud.google.com/appengine/docs/flexible/go/migrating#url_fetch

Related

Golang Wasm HTTP Request Failing

I'm a little stuck on a Golang wasm request. The code works just fine in a service when I test it, but when I try to run it in a browser with wasm I get a fetch failed error. This code runs just fine if I call it from a stand-alone service:
go func() {
authURL := "https://auth.home.rsmachiner.com/login"
type loginStruct struct {
Username string `json:"username"`
Password string `json:"password"`
}
fmt.Println("Pushed login button")
fmt.Printf("Got Login: %v\n", r.LoginBoxValue)
fmt.Printf("Got Password: %v\n", r.PasswordValue)
var login loginStruct
login.Username = r.LoginBoxValue
login.Password = r.PasswordValue
data, err := json.Marshal(&login)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(data))
req, _ := http.NewRequest("POST", authURL, bytes.NewBuffer(data))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("response error")
fmt.Println(err)
return
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Print("BODY:")
fmt.Println(string(body))
}()
Which throws the following error:
Post "https://auth.home.rsmachiner.com/login": net/http: fetch() failed: Failed to fetch
When I try it from a standalone client it works fine. The server is allowing CORS as well with
w.Header().Set("Access-Control-Allow-Origin", "*")
For anyone that stumbles on this, it works fine in a browser too. The problem was the HTML not the code. The HTML was making the page reload so the request was failing due to being terminated.

Google Cloud Text to Speech - Why is there a latency discrepancy between requests through the Go client library and the REST API?

My goal is to get the audioContent from my call to Google Cloud's Text to Speech in Base64. My current program makes the same exact call twice: once through Google's TTS client library, and the other through an authentication token which I have to HORRIBLY copy and paste from running the command gcloud auth application-default print-access-token. Obviously, as recommended by Google Cloud, I should be using the client library. The issue, as you can see in the terminal when I time the requests in both methods, is that the client library takes 4-5 times as long!!!
% go run main.go
[CLIENT LIBRARY took 586ms]
[REST API took 138ms]
The delay is consistently above 500ms whereas the request to the REST API is never above 200ms. Why is it client library is so slow and are there ways I can optimize the requests? I originally thought what was taking forever was the encoding into Base64, but when I timed it, the encoding took no more than 3ms. That being said, would requesting the audioContent be in Base64 String make the request faster? The TTS API documentation does not mention support of this for client side, so is it just not possible even?
Is there something wrong in how I'm using it? If I have to use the REST API for speed-sake, I also have the issue of needing to generate an authorization token in my program and constantly check and update when it expires. I've been manually using terminal to generate one then copy and paste it into my code. Is there a library in Go where I can generate an access/authentication token for my Google Cloud Rest API?
package main
import (
b64 "encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"context"
texttospeech "cloud.google.com/go/texttospeech/apiv1"
texttospeechpb "google.golang.org/genproto/googleapis/cloud/texttospeech/v1"
)
func audioFromClient(text string) {
ctx := context.Background()
client, err := texttospeech.NewClient(ctx)
if err != nil {
fmt.Println(err)
}
req := &texttospeechpb.SynthesizeSpeechRequest{
Input: &texttospeechpb.SynthesisInput{
InputSource: &texttospeechpb.SynthesisInput_Text{Text: text},
},
Voice: &texttospeechpb.VoiceSelectionParams{LanguageCode: "en-US"},
AudioConfig: &texttospeechpb.AudioConfig{
AudioEncoding: texttospeechpb.AudioEncoding_MP3,
},
}
resp, err := client.SynthesizeSpeech(ctx, req)
if err != nil {
fmt.Println(err)
}
audioContent := b64.StdEncoding.EncodeToString((resp.AudioContent))
_ = audioContent
// GOT THE AUDIO IN BASE64
}
func audioFromRest(text string) {
url := "https://texttospeech.googleapis.com/v1/text:synthesize"
method := "POST"
payload := strings.NewReader("{\n \"input\": {\n \"text\": \"Hello Gamers!\"\n },\n \"voice\": {\n \"languageCode\": \"en-US\",\n \"name\": \"en-US-Wavenet-A\",\n \"ssmlGender\": \"MALE\"\n },\n \"audioConfig\": {\n \"audioEncoding\": \"MP3\"\n }\n}")
client := &http.Client{}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
}
req.Header.Add("Authorization", "Bearer ********* ACCESS TOKEN *******")
req.Header.Add("Content-Type", "application/json")
res, err := client.Do(req)
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
_ = body
// GOT THE AUDIO IN BASE64
}
func main() {
start := time.Now()
audioFromClient("This a test!")
fmt.Printf("[CLIENT LIBRARY took %.0fms]\n", float64(time.Since(start))/1e6)
start = time.Now()
audioFromRest("This a test!")
fmt.Printf("[REST API took %.0fms]\n", float64(time.Since(start))/1e6)
}

how to send http request in golang to my own server

I'm writing a simple webserver in golang that gets/creates/edits/deletes a simple text file. I've written the function handlers and I'd like to test them by sending a request to the appropriate url and checking to see what happens. My code is as below:
func createHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]
body, _ := ioutil.ReadAll(r.Body)
fmt.Fprint(w, name)
ioutil.WriteFile(name, []byte(body), 0644)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/textFiles/{name}", createHandler).Methods("POST")
log.Fatal(http.ListenAndServe(":8080", r))
var url = "http://localhost:8080/textFiles/testFile.txt"
var text = []byte(`{"title":"this is an example."}`)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(text))
if err != nil {
panic(err)
}
client := &http.Client{}
client.Do(req)
}
Once this code is run, however, no new file is created. I've been googling but I can't find anything on this type of problem, where I'm sending a request to the server that I'm building within the same file. Help appreciated.
The client code is not executed. The callhttp.ListenAndServe(":8080", r) runs the server. The function only returns when there was an error running the server. If the function does return, then log.Fatal will exit the process.
One fix is to run the server in a goroutine. This will allow main goroutine to continue executing to the client code.
go func() {
log.Fatal(http.ListenAndServe(":8080", r))
}()
This may not fix the problem because there's no guarantee that server will run before the client makes the request. Fix this issue by creating the listening socket in the main function and running the server in a goroutine.
ln, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
go func() {
log.Fatal(http.Serve(ln, r))
}()
... client code as before
If the goal if this code is testing, then use httptest.Server. The example in the documentation show show to use the test server.

Initializing Firebase Admin in App Engine standard Golang

I'm on golang app engine standard. I keep getting a 403 error when I'm using a firebase. Here is the code I'm using for passing credentials for firebase. What is this api key? What am I doing wrong?
Error:
googleapi: Error 403: The request is missing a valid API key., forbidden
credJSON := []byte("{...json from firebase console...}")
creds, err := google.CredentialsFromJSON(ctx, credJSON, "https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/datastore",
"https://www.googleapis.com/auth/devstorage.full_control",
"https://www.googleapis.com/auth/firebase",
"https://www.googleapis.com/auth/identitytoolkit",
"https://www.googleapis.com/auth/userinfo.email")
if err != nil {
return err
}
ops = append(ops, option.WithCredentials(creds))
fbApp, err := fb.NewApp(ctx, &fb.Config{ProjectID: projectID}, ops...)
Turns out if you pass nil for config. The library figures out credentials on Google Cloud. So, here is the code:
fbApp, err := fb.NewApp(ctx, nil, ops...)
if err != nil {
return nil, err
}

How Can I Make the Go HTTP Client NOT Follow Redirects Automatically?

I'm currently writing some software in Go that interacts with a REST API. The REST API endpoint I'm trying to query returns an HTTP 302 redirect along with an HTTP Location header, pointing to a resource URI.
I'm trying to use my Go script to grab the HTTP Location header for later processing.
Here's what I'm currently doing to achieve this functionality:
package main
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
)
var BASE_URL = "https://api.example.com/v1"
var STORMPATH_API_KEY_ID = "xxx"
var STORMPATH_API_KEY_SECRET = "xxx"
func noRedirect(req *http.Request, via []*http.Request) error {
return errors.New("Don't redirect!")
}
func main() {
client := &http.Client{
CheckRedirect: noRedirect
}
req, err := http.NewRequest("GET", BASE_URL+"/tenants/current", nil)
req.SetBasicAuth(EXAMPLE_API_KEY_ID, EXAMPLE_API_KEY_SECRET)
resp, err := client.Do(req)
// If we get here, it means one of two things: either this http request
// actually failed, or we got an http redirect response, and should process it.
if err != nil {
if resp.StatusCode == 302 {
fmt.Println("got redirect")
} else {
panic("HTTP request failed.")
}
}
defer resp.Body.Close()
}
This feels like a bit of a hack to me. By overriding the http.Client's CheckRedirect function, I'm essentially forced to treat HTTP redirects like errors (which they aren't).
I've seen several other places suggesting to use an HTTP transport instead of an HTTP client -- but I'm not sure how to make this work since I need the HTTP Client as I need to use HTTP Basic Auth to communicate with this REST API.
Can any of you tell me a way to make HTTP requests with Basic Authentication -- while not following redirects -- that doesn't involve throwing errors and error handling?
There's a much simpler solution right now:
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
This way, the http package automatically knows: "Ah, I shouldn't follow any redirects", but does not throw any error. From the comment in the source code:
As a special case, if CheckRedirect returns ErrUseLastResponse,
then the most recent response is returned with its body
unclosed, along with a nil error.
Another option, using the client itself, without the RoundTrip:
// create a custom error to know if a redirect happened
var RedirectAttemptedError = errors.New("redirect")
client := &http.Client{}
// return the error, so client won't attempt redirects
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return RedirectAttemptedError
}
// Work with the client...
resp, err := client.Head(urlToAccess)
// test if we got the custom error
if urlError, ok := err.(*url.Error); ok && urlError.Err == RedirectAttemptedError{
err = nil
}
UPDATE: this solution is for go < 1.7
It is possible, but the solution inverts the problem a little. Here's a sample written up as a golang test.
package redirects
import (
"github.com/codegangsta/martini-contrib/auth"
"github.com/go-martini/martini"
"net/http"
"net/http/httptest"
"testing"
)
func TestBasicAuthRedirect(t *testing.T) {
// Start a test server
server := setupBasicAuthServer()
defer server.Close()
// Set up the HTTP request
req, err := http.NewRequest("GET", server.URL+"/redirect", nil)
req.SetBasicAuth("username", "password")
if err != nil {
t.Fatal(err)
}
transport := http.Transport{}
resp, err := transport.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
// Check if you received the status codes you expect. There may
// status codes other than 200 which are acceptable.
if resp.StatusCode != 200 && resp.StatusCode != 302 {
t.Fatal("Failed with status", resp.Status)
}
t.Log(resp.Header.Get("Location"))
}
// Create an HTTP server that protects a URL using Basic Auth
func setupBasicAuthServer() *httptest.Server {
m := martini.Classic()
m.Use(auth.Basic("username", "password"))
m.Get("/ping", func() string { return "pong" })
m.Get("/redirect", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/ping", 302)
})
server := httptest.NewServer(m)
return server
}
You should be able to put the above code into it's own package called "redirects" and run it after fetching the required dependencies using
mkdir redirects
cd redirects
# Add the above code to a file with an _test.go suffix
go get github.com/codegangsta/martini-contrib/auth
go get github.com/go-martini/martini
go test -v
Hope this helps!
To make request with Basic Auth that does not follow redirect use RoundTrip function that accepts *Request
This code
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
var DefaultTransport http.RoundTripper = &http.Transport{}
req, _ := http.NewRequest("GET", "http://httpbin.org/headers", nil)
req.SetBasicAuth("user", "password")
resp, _ := DefaultTransport.RoundTrip(req)
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
}
fmt.Printf("%s\n", string(contents))
}
outputs
{
"headers": {
"Accept-Encoding": "gzip",
"Authorization": "Basic dXNlcjpwYXNzd29yZA==",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "Go 1.1 package http",
"X-Request-Id": "45b512f1-22e9-4e49-8acb-2f017e0a4e35"
}
}
As an addition of top rated answer,
You can control the particle size
func myCheckRedirect(req *http.Request, via []*http.Request, times int) error {
err := fmt.Errorf("redirect policy: stopped after %d times", times)
if len(via) >= times {
return err
}
return nil
}
...
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return myCheckRedirect(req, via, 1)
},
}
ref: https://golangbyexample.com/http-no-redirect-client-golang/

Resources