# 36 HTTP客户端

标准库中的`net/http`包提供了发起HTTP请求的功能。

在示例中，我们使用[httpbin.org](https://httpbin.org)，它是一个聪明的HTTP服务，可以返回指定的HTTP响应，它用于演示HTTP协议的各个方面非常便利。

## 基本的GET请求

`http.Get()`只是`http.DefaultClient`的封装，后者是`*http.Client`类型的变量打包。

最好不要使用`http.Get`，因为它默认是没有超时的，这意味着它在连接到慢的或有缺陷的或恶意的服务上时永远等待。

{% hint style="danger" %}
**译者注**：对于网络服务来说，慢比错更可怕。慢意味着不确定性，如果不设置合适的超时限制，服务将被拖垮。
{% endhint %}

```go
package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

func main() {
	client := &http.Client{}
	client.Timeout = time.Millisecond * 100

	uri := "https://httpbin.org/delay/3"
	resp, err := client.Get(uri)
	if err != nil {
		log.Fatalf("http.Get() failed with '%s'\n", err)
	}
	fmt.Println(resp)
}
```

如上所示，创建和使用自定义的`http.Client`是很容易的。

在上例中，我们设置了非常短的超时限制，以此演示因超时而取消连接。

在实际编程中，应该采用更长的超时时间，比如15秒（确切的超时时长应视情况而定）。

## 基本的POST请求

{% tabs %}
{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

func main() {
	client := &http.Client{}
	client.Timeout = time.Second * 15

	uri := "https://httpbin.org/post"
	body := bytes.NewBufferString("text we send")
	resp, err := client.Post(uri, "text/plain", body)
	if err != nil {
		log.Fatalf("client.Post() failed with '%s'\n", err)
	}
	defer resp.Body.Close()
	d, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("http.Get() failed with '%s'\n", err)
	}
	fmt.Printf("http.Post() returned statuts code %d, truncated text:\n%s...\n", resp.StatusCode, string(d)[:93])
}

```

{% endtab %}

{% tab title="Output" %}

```
http.Post() returned statuts code 200, truncated text:
{
  "args": {}, 
  "data": "text we send", 
  "files": {}, 
  "form": {}, 
  "headers": {
   ...

```

{% endtab %}
{% endtabs %}

发起POST最简单的方法是使用`http.Client.Post(url string, contentType string, body io.Reader)`。

在上例中，我们发送了原始文本。在大多数情况下，服务端期望请求体是URL编码(Url-Encoded)后的格式。

## 基本的HEAD请求

跟GET用法一样，只改一下方法名`http.Client.Head(uri string)`。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://denglj.gitbook.io/essential-go/common-standard-libraries/36-http-client.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
