Go'daki bir POST isteğinde nasıl JSON dizesi gönderirim?


244

Apiary ile çalışmayı denedim ve sahte sunucuya JSON göndermek ve bu kodu var evrensel bir şablon yaptım:

package main

import (
    "encoding/json"
    "fmt"
    "github.com/jmcvetta/napping"
    "log"
    "net/http"
)

func main() {
    url := "http://restapi3.apiary.io/notes"
    fmt.Println("URL:>", url)

    s := napping.Session{}
    h := &http.Header{}
    h.Set("X-Custom-Header", "myvalue")
    s.Header = h

    var jsonStr = []byte(`
{
    "title": "Buy cheese and bread for breakfast."
}`)

    var data map[string]json.RawMessage
    err := json.Unmarshal(jsonStr, &data)
    if err != nil {
        fmt.Println(err)
    }

    resp, err := s.Post(url, &data, nil, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("response Status:", resp.Status())
    fmt.Println("response Headers:", resp.HttpResponse().Header)
    fmt.Println("response Body:", resp.RawText())

}

Bu kod JSON'u düzgün göndermiyor, ancak nedenini bilmiyorum. JSON dizesi her çağrıda farklı olabilir. Bunun Structiçin kullanamam .


Kullandığınız bazı kütüphanelere aşina değilim, ama anladığım kadarıyla, bir Jsons haritası göndermeye çalışıyorsunuz. Neden sadece json ile ipi göndermiyorsun?
Topo

1
Eğer json göndermek istiyorsanız neden json unmarshaling?
JimB

Küçük bir ipucu, mesajınızı istediğiniz tüm değerleri eklemek için bir yapı veya harita [string] arayüzü {} olarak oluşturabilir ve ardından haritayı veya yapıyı bir json'a dönüştürmek için json.Marshall kullanabilirsiniz.
Topo

@top, uyuklama kaynak kodu içine kazdık, eğer yük ayarlanmışsa, onlar çağırmak json.Marshall, neden onun için çalışmıyor emin değilim.
OneOfOne

Yanıtlar:


502

Uyuklamaya aşina değilim, ancak Golang'ın net/httppaketini kullanmak iyi çalışıyor ( oyun alanı ):

func main() {
    url := "http://restapi3.apiary.io/notes"
    fmt.Println("URL:>", url)

    var jsonStr = []byte(`{"title":"Buy cheese and bread for breakfast."}`)
    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
    req.Header.Set("X-Custom-Header", "myvalue")
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println("response Status:", resp.Status)
    fmt.Println("response Headers:", resp.Header)
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println("response Body:", string(body))
}

1
şimdi oyun alanında panik var. Bir şeyi düzeltmek veya güncellemek için shold olabilir misiniz?
Altenrion

9
@Altenrion oyun alanında çalışamaz, sadece kodu yapıştırmak için kullandım, dış bağlantıları açamazsınız.
OneOfOne

8
Katı bant adı önerisi için @Altenrion +1.
Charlie Schliesser

8
Sadece bir uyarı, varsayılan olarak golang http istemcisinin asla zaman aşımına uğramamasını unutmayın, bu yüzden gerçek dünya için, çizgiler boyunca bir şey ayarlamak için en iyisiclient.Timeout = time.Second * 15
svarlamov

1
Bu, tüm hatalarını toplamak / incelemek için güncellenebilir mi? Bu (en azından benim için) Go'da posta istekleri yapmak için google'da en iyi sonuç ve iyi bir cevap, ancak sadece hataları görmezden gelen bir ton örnek kod görüyorum ve yeni başlayanlarda kötü uygulamayı teşvik ettiğini düşünüyorum. Sonra yine, eğer birisi düzenli olarak hataları görmezden gelirse, nihayetinde niçin olmamak gerektiğini öğrenecekler, ama neden iyi uygulamayı başlamaya teşvik etmiyorlar?
K. Rhoda

103

postjson'unuzu göndermek için kullanabilirsiniz .

values := map[string]string{"username": username, "password": password}

jsonValue, _ := json.Marshal(values)

resp, err := http.Post(authAuthenticatorUrl, "application/json", bytes.NewBuffer(jsonValue))

3
Bu hatayı alıyorum:cannot use jsonValue (type []byte) as type io.Reader in argument to http.Post: []byte does not implement io.Reader (missing Read method)
Mandar Vaze

@MandarVaze i yanlış alabilirsiniz düşünmek io.Readeriçin http.Post, ve bytes.NewBuffer () benim kod iyi çalışır
gaozhidf

1
Önemlidir 1.7, eğer önemliyse. @OneOfOne tarafından listelenen kod çalışır (bunun yerine kullanır, bytes.NewBuffer()ancak kullanır )http.NewRequesthttp.Post
Mandar Vaze

2
Golang.org/pkg/net/http/#Post'a göre , "Arayan resp.Bodyondan okurken bitirmelidir . Sağlanan gövde bir ise io.Closer, istek sonrasında kapatılır." Bir Go acemi olarak, vücudun bir olduğunu io.Closerveya başka bir deyişle, bu örneğin güvenli olup olmadığını nasıl anlayabilirim ?
Dennis

14

Zaten bir yapınız varsa.

type Student struct {
    Name    string `json:"name"`
    Address string `json:"address"`
}

// .....

body := &Student{
    Name:    "abc",
    Address: "xyz",
}

buf := new(bytes.Buffer)
json.NewEncoder(buf).Encode(body)
req, _ := http.NewRequest("POST", url, buf)

client := &http.Client{}
res, e := client.Do(req)
if e != nil {
    return e
}

defer res.Body.Close()

fmt.Println("response Status:", res.Status)
// Print the body to the stdout
io.Copy(os.Stdout, res.Body)

Tam gist .


12

Standart net / http paketine ek olarak, GoRequest'imi saran ve json veya struct hakkında fazla düşünmeden hayatınızı kolaylaştıran . Ancak her ikisini de tek bir istekte karıştırabilir ve eşleştirebilirsiniz! (bunun hakkında daha fazla ayrıntıyı gorequest github sayfasında görebilirsiniz)

Böylece, sonunda kod aşağıdaki gibi olacak:

func main() {
    url := "http://restapi3.apiary.io/notes"
    fmt.Println("URL:>", url)
    request := gorequest.New()
    titleList := []string{"title1", "title2", "title3"}
    for _, title := range titleList {
        resp, body, errs := request.Post(url).
            Set("X-Custom-Header", "myvalue").
            Send(`{"title":"` + title + `"}`).
            End()
        if errs != nil {
            fmt.Println(errs)
            os.Exit(1)
        }
        fmt.Println("response Status:", resp.Status)
        fmt.Println("response Headers:", resp.Header)
        fmt.Println("response Body:", body)
    }
}

Bu, nasıl başarmak istediğinize bağlıdır. Bu kütüphaneyi yaptım çünkü sizinle aynı problemim var ve kod tabanım ve üretim sistemimde daha kısa, json ile kullanımı kolay ve daha sürdürülebilir kod istiyorum.


GoRequest net / http'yi sararsa. TLS için Güvenli Olmayan sertifikayı devre dışı bırakmak için bunu eklemek mümkün müdür? tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }
user1513388

46
@ user1513388 TLS doğrulamasını herhangi bir dilde herhangi bir senaryoda atlamak için kod örneklerine katkıda bulunmak her zaman korkunç bir fikirdir ... StackOverflow'u ziyaret eden ve neden düzeltmenin doğasını anlamadığınızı yanlışlıkla kopyala / yapıştır "geçici çözümlerini" kalıcı olarak uygularsınız TLS hataları çok önemlidir. Sertifika içe aktarma yolunuzu (test için kendinden imzalı kullanıyorsanız, bunları içe aktarın) veya makinenizin sertifika zincirini düzeltin ya da sunucunuzun neden istemciniz tarafından doğrulanamayan geçersiz bir sertifika sunduğunu öğrenin.
Mike Atlas

1
Bu cevap hakkında tam olarak sevmediğim bir şey, enjeksiyon yoluyla potansiyel olarak sömürülebilir olan JSON nesnesini oluşturma biçimidir. Daha iyi bir yol, bir nesne oluşturmak ve daha sonra onu JSON'a dönüştürmektir (uygun çıkış ile).
John White

@JohnWhite Kabul ediyorum, çok yakut hissediyor / js / pythonic
Rambatino
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.