go语言HTTP GET解析URL中的查询参数

go语言HTTP GET解析URL中的查询参数

经常我们会使用下面的逻辑来处理查询参数:

func myHandler(w http.ResponseWriter, r *http.Request) {
    vars := r.URL.Query();
    a := vars["a"][0]
    ...
}

描述起来很简单,先获取Query对象,然后从Query对象里面根据名字解析到一个参数,再取其中的第一个元素值。

下面我们仔细了解一下这几个数据对象:

Query() 是什么对象

语句 vars := r.URL.Query() 返回的vars是一个什么对象?

Query函数的定义是是这样的:

# net/url/url.go
func (u *URL) Query() Values {
    v, _ := ParseQuery(u.RawQuery)
    return v
}

// Query is expected to be a list of key=value settings separated by
// ampersands or semicolons. A setting without an equals sign is
// interpreted as a key set to an empty value.
func ParseQuery(query string) (Values, error) {
    m := make(Values)
    err := parseQuery(m, query)
    return m, err
}

// Values maps a string key to a list of values.
// It is typically used for query parameters and form values.
// Unlike in the http.Header map, the keys in a Values map
// are case-sensitive.
type Values map[string][]string

这里我们可以看到Query()返回的Values实际上是一个map对象,这个map的key是字符串,value是字符串数组,正好是参数名到参数值数组的map关系,因为同一个参数名可以有多个值,所有参数值是一个字符串数组。例如:
map[“A”] = [“A1”]
map[“B”] = [“B1”, “B2”]

另外我们从代码看到vars不能为空nil值,虽然vars里面的成员可以为空,也就是说如果URL里面没有查询参数,那么vars的成员为空,即大小为0,但vars本身不为nil。

如何解析参数值

第一种原始方法遍历解析Query对象的成员。

  vars := r.URL.Query();
  a, ok := vars["a"]
  if !ok {
    fmt.Printf("param a does not exist\n");
  } else {
    fmt.Printf("param a value is [%s]\n", a);
  }

几个例子:

URLResult
curl http://localhost:8080/api/service/getparam a does not exist
curl http://localhost:8080/api/service/get?aparam a value is [[]]
curl http://localhost:8080/api/service/get?a=param a value is [[]]
curl http://localhost:8080/api/service/get?a=a1param a value is [[a1]]
curl http://localhost:8080/api/service/get?a=a2&a=a2param a value is [[a1 a2]]

从上述例子,我们可以看到a的类型是一个数组,即使是没有值,也是一个空数组。

使用Get方法解析参数

Get方法是专门用来处理只有一个参数的参数值,即当参数不存在是返回空串(“”),当参数存在多个值时返回第一个值。
Get方法的定义如下:

// Get gets the first value associated with the given key.
// If there are no values associated with the key, Get returns
// the empty string. To access multiple values, use the map
// directly.
func (v Values) Get(key string) string {
    if v == nil {
        return ""
    }
    vs := v[key]
    if len(vs) == 0 {
        return ""
    }
    return vs[0]
}

重新验证上面的代码逻辑:

  v := r.URL.Query();
  a := v.Get("a")
  fmt.Printf("param a value is [%s]\n", a);

运行结果

URLResult
curl http://localhost:8080/api/service/getparam a value is []
curl http://localhost:8080/api/service/get?aparam a value is []
curl http://localhost:8080/api/service/get?a=param a value is []
curl http://localhost:8080/api/service/get?a=a1param a value is [a1]
curl http://localhost:8080/api/service/get?a=a2&a=a2param a value is [a1]

可以看到如果参数不存在Get方法函数空串,当有多个参数时Get方法返回第一个值。
相比较前面一种方法,Get不需要考虑空数组越界的问题,如果不存在就返回空串即可。

    原文作者:CodingCode
    原文地址: https://www.jianshu.com/p/1075211f0556
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞