2015-04-23 3 views
0

Я пытаюсь возобновить загрузку, как описано here.Ошибка повторной загрузки Google Analytics

Когда я выполняю загрузку, я получаю статус ответа 400 Bad Request, и тело отклика:

{ 
    "error": { 
     "errors": [ 
      { 
       "domain": "global", 
       "reason": "badContent", 
       "message": "Unsupported content with type: application/octet-stream" 
      } 
     ], 
     "code": 400, 
     "message": "Unsupported content with type: application/octet-stream" 
    } 
} 

Сценарий я использую для выполнения загрузки в Go, здесь:

package main 

import(
    "bytes" 
    "fmt" 
    "io" 
    "io/ioutil" 
    "mime/multipart" 
    "net/http" 
    "os" 
    "path/filepath" 
) 

func main(){ 

    // config 
    accessToken := "a valid token" 
    acctId := "a valid account id" 
    webPropertyId := "a valid web property id" 
    customDataSourceId := "a valid custom data source id" 
    path := "https://stackoverflow.com/a/path/to/a/validly/formatted/file.csv" 
    params := map[string]string{ 
     "title":  "My Document", 
     "author":  "Becca Petrin", 
     "description": "Riveting stuff", 
    } 
    paramName := "file" 
    url := fmt.Sprintf("https://www.googleapis.com/upload/analytics/v3/management/accounts/%s/webproperties/%s/customDataSources/%s/uploads?uploadType=resumable", acctId, webPropertyId, customDataSourceId) 

    // create the body 
    file, err := os.Open(path) 
    if err != nil { 
     fmt.Println("Err opening file:", err.Error()) 
     return 
    } 
    defer file.Close() 

    body := &bytes.Buffer{} 
    writer := multipart.NewWriter(body) 
    part, err := writer.CreateFormFile(paramName, filepath.Base(path)) 
    if err != nil { 
     fmt.Println("Err creating form file:", err.Error()) 
     return 
    } 

    _, err = io.Copy(part, file) 
    if err != nil { 
     fmt.Println("Err copying:", err.Error()) 
     return 
    } 

    for k, v := range params { 
     _ = writer.WriteField(k, v) 
    } 

    if err := writer.Close(); err != nil { 
     fmt.Println("Err closing writer:", err.Error()) 
     return 
    } 

    req, err := http.NewRequest("POST", url, body) 
    if err != nil { 
     fmt.Printf("Err creating request:", err.Error()) 
     return 
    } 

    // add authorization 
    req.Header.Set("Authorization", "Bearer "+accessToken) 

    // add headers 
    // no multipart headers work, and "application/octet-stream"" doesn't work 
    // uncommenting and using "text/plain" results in a 200 without the expected response body 
    //req.Header.Add("Content-Type", "text/plain") 

    // execute request 
    client := &http.Client{} 
    resp, err := client.Do(req) 
    if err != nil { 
     fmt.Println("Err doing request:", err.Error()) 
     return 
    } 

    fmt.Println("Response status:", resp.Status) 
    b, err := ioutil.ReadAll(resp.Body) 
    if err != nil { 
     fmt.Println("Err reading resp body:", err.Error()) 
     return 
    } 
    fmt.Printf("Response body: %s", b) 
} 

Как было отмечено в комментариях, я получаю неподдерживаемый ответ типа контента, если не включать в себя заголовок Content-Type. Я также получаю его, если я использую какие-либо типы многостраничного контента, или application/octet-stream. Если я использую text/plain, я получаю 200, но я не получаю ожидаемого тела.

Что я делаю неправильно? Заранее спасибо!

ответ

0

я решил взять альтернативный подход к этому, пытаясь через клиентскую библиотеку Google Go, и я получил его работать с этим фрагментом:

package main 


import (

    "errors" 
    "fmt" 
    "os" 
    "time" 

    google "google.golang.org/api/analytics/v3" 
    "golang.org/x/oauth2" 
) 

var (
    accessToken = "a valid token" 
    acctId = "a valid account ID" 
    webPropertyId = "a valid web property ID" 
    customDataSourceId = "a valid custom data source ID" 
    filePath = "/path/to/file.csv" 
) 

func main(){ 

    ctx1 := NewCallContext() 
    tokenSource := TokenSource{} 
    httpClient := oauth2.NewClient(ctx1, &tokenSource) 

    service, err := google.New(httpClient) 
    if err != nil { 
     fmt.Println("Err making client:", err.Error()) 
     return 
    } 

    r, err := NewFileReader(filePath) 
    if err != nil { 
     fmt.Println("Err making reader:", err.Error()) 
     return 
    } 

    ctx2 := NewCallContext() 
    call := service.Management.Uploads.UploadData(acctId, webPropertyId, customDataSourceId) 
    call = call.ResumableMedia(ctx2, r, 10, "application/octet-stream") 

    upload, err := call.Do() 
    if err != nil { 
     fmt.Println("Err doing call: %v", err) 
     return 
    } 

    fmt.Printf("%s", upload) 
} 


// http://golang.org/pkg/io/#ReaderAt 
func NewFileReader(pathToFile string) (*FileReader, error) { 
    f, err := os.Open(pathToFile) 
    if err != nil { 
     return nil, err 
    } 
    return &FileReader{f}, nil 
} 

type FileReader struct { 
    f *os.File 
} 

func (s *FileReader) ReadAt(p []byte, off int64) (int, error) { 
    return s.f.ReadAt(p, off) 
} 

// https://godoc.org/golang.org/x/net/context#Context 
func NewCallContext() *CallContext { 
    c := make(<-chan struct{}) 
    return &CallContext{c} 
} 

type CallContext struct { 
    doneChan <-chan struct{} 
} 

func (s *CallContext) Deadline() (time.Time, bool) { 
    return time.Now().Add(time.Duration(10) * time.Second), true 
} 

func (s *CallContext) Done() <-chan struct{} { 
    return s.doneChan 
} 

func (s *CallContext) Err() error { 

    select { 
    case <- s.doneChan: 
     return errors.New("Done") 
    default: 
    } 
    return nil 
} 

func (s *CallContext) Value(key interface{}) interface{} { 
    return nil 
} 

// satisfies the oauth2 tokensource interface 
type TokenSource struct {} 

func (t *TokenSource) Token() (*oauth2.Token, error) { 
    return &oauth2.Token{AccessToken:accessToken}, nil 
} 
Смежные вопросы