2016-11-08 21 views
1

如何從具有多個逗號分隔值的標頭獲取值。例如,具有多個值的golang http解析標頭

url := "https://accounts.google.com/.well-known/openid-configuration" 
resp, err := http.Get(url) 
field := resp.Header.Get("Cache-Control") // "public, max-age=3600" 

在這種情況下,我想獲得max-age值。我看到兩種情況:使用strings.Split()Trim()和等

  • (我認爲這不是個好主意)使用bufio.Scanner
  • SplitFunc(更好一點)

任何好的想法或最佳實踐?

編輯1.使用strings.FieldsFunc()

const input = " public,max-age=3000, anothercase " 

sep := func(c rune) bool { 
    return c == ',' || c == ' ' 
} 
values := strings.FieldsFunc(input, sep) 

關於基準

BenchmarkTrim-4 2000000 861 ns/op 48 B/op 1 allocs/op 

編輯2.使用Scaner()

因此,讓基準它

func ScanHeaderValues(data []byte, atEOF bool) (advance int, token []byte, err error) { 
    // Skip leading spaces. 
    var start int 
    for start = 0; start < len(data); start++ { 
     if data[start] != ' ' { 
      break 
     } 
    } 
    // Scan until comma 
    for i := start; i < len(data); i++ { 
     if data[i] == ',' { 
      return i + 1, data[start:i], nil 
     } 
    } 
    // If we're at EOF, we have a final, non-empty, non-terminated word. Return it. 
    if atEOF && len(data) > start { 
     return len(data), data[start:], nil 
    } 
    // Request more data. 
    return start, nil, nil 
} 

func BenchmarkScanner(b *testing.B) { 
    const input = " public,max-age=3000, anothercase " 
    scanner := bufio.NewScanner(strings.NewReader(input)) 
    split := func(data []byte, atEOF bool) (advance int, token []byte, err error) { 
     advance, token, err = ScanHeaderValues(data, atEOF) 
     return 
    } 
    scanner.Split(split) 

    b.ResetTimer() 
    for i := 0; i < b.N; i++ { 
     for scanner.Scan() { 
      // a := scanner.Text() 
      // b.Logf("%+v\n", a) 
     } 
    } 
} 

而且結果:

BenchmarkTrim-4  2000000 861 ns/op 48 B/op 1 allocs/op 
BenchmarkScanner-4 50000000 21.2 ns/op 0 B/op 0 allocs/op 

如果您有任何其他更好的解決辦法,我想看到它。

+4

爲什麼'Split'和'Trim' /'TrimSpace'不是一個好主意? – JimB

+0

@JimB我想我會得到更多的內存分配,我可以通過使用'Scanner'來避免。 – BBQTD

+1

你不能使用任何簡單的字符串拆分,因爲緩存控制值可以使用帶引號的字符串語法,這將允許在一個值內使用「,」 –

回答

-1

沒有錯:

url := "https://accounts.google.com/.well-known/openid-configuration" 
resp, err := http.Get(url) 
fields := strings.Split(resp.Header.Get("Cache-Control"), ",") 
for i, field := range field { 
    fields[i] = strings.Trim(field, " ") 
} 

編輯:編輯現在只要逗號後的空間缺少

+0

對於有效的頭部值'public,max-age = 3600 '。 –

+0

@MellowMarmot是正確的。我一直認爲這個空間是必需的,但規格說明不然(https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) – TheHippo

+0

@TheHippo這不是規範(不再) –