golang网络编程day4

golang网络编程day4

  • get和post的区别
  • resful编程
  • golang请求头
  • golangheader内容类型和字符编码
  • http请求头缓存和过期应用
  • golang 请求头跨域请求应用
  • http请求头用户代理应用
  • golang响应头

get和post的区别

在前面的学习我只在应用场景上做了一个区别的举例,这里是进一步的学习有哪些区别.

但是首先要知道两种都是HTTP协议的常见请求方法

区别:
1.参数位置: GET请求将参数包含在URL中,而POST请求将参数包含在请求体中,因此GET请求的参数会在URL中可见,Post请求的参数则不可见.
2. 参数长度: GRT请求的参数长度有限制,最长不能超过2048个字符,而POST没有参数长度限制
3. 安全性: 由于GET请求将参数包含在URL中,因此参数会被浏览器缓存,历史记录等信息中存储.这就可能导致敏感信息泄露的安全问题,而POST请求将参数包含在请求体中,参数不会被缓存,因此相对更安全.
4. **缓存:**由于GET请求的参数在URL中可见,因此浏览器可以换成GET请求的结果,从而提高新年,而POST请求的结果无法被缓存,因为相同的请求可能产生不同的结果
5. 幂等性: GET请求是幂等的,即对于相同的URL和参数,多次请求得到的结果都是相同的,而POST请求不是幂等的,即多次请求可能会得到不同的结果,因为每次请求都可能会修改服务器上的数据.

总之:两个请求的选择应该根据需求和业务场景来进行选择,考虑的因素就是上面这五个因素,可以作为参考.在通常情况下,GET用于请求数据,POST用于提交数据.

应用场景实例:
场景1:用户注册: 比如用户在注册页面正在填写注册表单,当点击提交后,就会发生HTTP请求的发送,这里来看看好坏:
GET 请求:在注册页面输入用户名、密码等信息后,点击“提交”按钮时,会向服务器发送一个 GET 请求,请求的 URL 包含用户注册信息的参数,例如:http://example.com/register?username=testuser&password=123456。

这里显然你会发现GET请求将参数包含在了URL中,是不是就显得不安全,

POST 请求:在注册页面输入用户名、密码等信息后,点击“提交”按钮时,会向服务器发送一个 POST 请求,请求体中包含用户注册信息的参数,例如:

POST /register HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=testuser&password=123456

Post请求将参数放到请求体里面去了,这样就显得比上一种安全的多.

场景2: 用户登录 :
GET 请求:在登录页面输入用户名、密码等信息后,点击“登录”按钮时,会向服务器发送一个 GET 请求,请求的 URL 包含用户登录信息的参数,例如:http://example.com/login?username=testuser&password=123456。

我输入完密码点登录,这个时候会发HTTP请求,如果是GET类型,会发现作为参数的密码暴露在了URL中.显得十分的不安全.

**POST 请求:**在登录页面输入用户名、密码等信息后,点击“登录”按钮时,会向服务器发送一个 POST 请求,请求体中包含用户登录信息的参数,例如:

POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=testuser&password=123456

敏感信息都到请求体里面去了.

综上,这两种方法在实际应用中,通常都会考虑到用户数据的安全性来作为使用的前提,因此还会涉及到HTTPS等安全协议来保证数据的加密和传输安全.


restful编程

先来看看restful是个啥:(Representational State Transfer),一种软件架构风格的设计原则,它通过统一的接口来处理资源的状态和操作.在RESTful架构中,每个资源都由一个URI表示,而资源的状态则通过HTTP请求方法来表示,常用的HTTP请求方法包括GET/POST/PUT/DELETE等.以下是RESTful编程的特点:

1.资源标识符:RESTful架构中,每个资源都由一个唯一的URI表示,URI应该是简洁,易于理解,并且具有一定的可读性.
2.统一的接口:RESTful结构中的每个资源都是以相同的HTTP请求方法来操作,从而使接口具有统一的格式和风格.
3.无状态性:RESTful架构中的请求和响应都是无状态的,即每个请求和响应都应该包含足够的信息,以便独立地处理请求和响应,不需要依赖上下文信息.
4.可缓存性:RESTful架构中的响应应该是可缓存的,即客户端可以缓存响应以提高性能,并且可以使用缓存机制来降低服务器的负载.
5.分层系统:RESTful架构中的系统应该是分层的,即客户端和服务器之间可以存在多个中间层,这些中间层可以提供负载均衡,缓存,安全等功能.
6.按需编码:RESTful架构中的客户端和服务器应该可以独立地演化,即客户端和服务器可以根据需要选择使用特定的格式和协议以便更好的满足自己的需求.

总之:RESTful架构提供了一种简单灵活可扩展的方式来设计和构建分布式系统,它强调资源的状态和操作,使得系统具有统一的接口和格式,从而提高了系统的可重用性,可维护性,和可扩展性.

下面看一个RESTful API实例:
假设有一个电影列表应用,用户可以通过API获取电影列表/添加电影/修改电影/删除电影等操作.

1,获取电影列表
请求方式:GET
请求 URL:http://example.com/movies
请求参数:无
响应结果:

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": 1,
    "title": "The Shawshank Redemption",
    "year": 1994,
    "director": "Frank Darabont"
  },
  {
    "id": 2,
    "title": "The Godfather",
    "year": 1972,
    "director": "Francis Ford Coppola"
  },
  ...
]

2.添加电影
请求方式:POST
请求 URL:http://example.com/movies
请求参数:

{
  "title": "The Dark Knight",
  "year": 2008,
  "director": "Christopher Nolan"
}

响应结果:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": 10,
  "title": "The Dark Knight",
  "year": 2008,
  "director": "Christopher Nolan"
}

3.修改电影
请求方式:PUT
请求 URL:http://example.com/movies/10
请求参数:

{
  "title": "The Dark Knight Rises",
  "year": 2012,
  "director": "Christopher Nolan"
}

响应结果:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 10,
  "title": "The Dark Knight Rises",
  "year": 2012,
  "director": "Christopher Nolan"
}

3.删除电影
请求方式:DELETE
请求 URL:http://example.com/movies/10
请求参数:无
响应结果:

HTTP/1.1 204 No Content

上面这些例子是一些举例,关于这个RESTful,先知道有这回事就行了,然后知道它是一种设计原则.


golang请求头

昨天在学习Http编程那里可以了解到,请求头这个东西,你甚至可以按照需求自定义请求头,自己设置请求头来传递一些额外的信息,看看下面这个例子:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    req, err := http.NewRequest("GET", "https://example.com", nil)
    if err != nil {
        panic(err)
    }

    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3")
    req.Header.Set("Authorization", "Bearer xxxxxxxxxxxxxxxxxxxxxxx")

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

    fmt.Println(resp.Status)
}

解读:
req, err := http.NewRequest(“GET”, “https://example.com”, nil)
net/http包下的一个函数,这个函数的功能很重要,用于构建一个新的http请求,
参数:
请求方法,URL,请求体
对于GET请求,通常没有请求体,所以这里使用nil,对于其他类型的请求,比如POST和PUT,这个请求体可以放要发送的数据.
返回值:
req:一个指向http.Request结构体的指针,这个结构体包含了与HTTP请求相关的信息,例如URL,头部,请求体等(可以说这个req就是构建的请求,我们也知道http的请求时包含很多部分的,这里用这个结构体来表示了,那些部分都是这个结构体的字段.)

拿到这个req有什么好处,通过这个请求对象,我可以进一步的修改请求,例如我可以添加更多的头部字段,或者在需要的时候修改URL,之后,这个请求对象可以被用于实际发送到请求的服务器中.比如通过http.Client的Do方法.

req.Header.Set(“User-Agent”, “…”)
req.Header.Set(“Authorization”, “Bearer xxxxxxxxxxxxxxxxxxxxxxx”)

这个 就是给这个请求对象添加更多的头部字段.

client := http.DefaultClient
resp, err := client.Do(req)

创建HTTP客户端并发送请求

http.DefaultClient
这个是net/http包中预定的一个客户端实例,他是*http.Client类型的,提供了一个基本的HTTP客户端的,可以用于发送请求和接收响应.
http.Client结构体包含了一些配置,如超时设置/Cookie处理,重定向策略等,DefaultClient使用默认的配置,适用于大多数的场景.

*http.Client解读:这个是个结构体,代表了HTTP客户端实例,它提供了一系列方法来发送HTTP请求和接收响应.
功能: 这个客户端能够处理所有类型的HTTP请求,它可以被配置来处理请求的具体细节,例如超时时间,Cookie,重定向策略等.
默认客户端和自定义客户端:go语言提供了一个默认的客户端实例http.DefaultClient,它使用了默认配置,适用于大多数基本用途.
当然这里我也可以创建一个自定义的http.client实例,并根据需要配置其属性.

那么怎么配置属性?
那当然就是这个结构体的字段来配置了,你要用这个字段你就在创建客户端实例的时候进行自己想要的初始化.

下面是几个http.Client的重要属性和相关方法:

Timeout:
这个字段设置 HTTP 请求的超时时间。如果在指定时间内未收到响应,请求将被取消。

Transport:
用于管理 HTTP 请求的底层传输细节。例如,可以配置它来使用不同的协议版本,设置代理,管理 TLS 配置等。

CheckRedirect:
一个可选的函数,用于控制处理 HTTP 重定向的行为。你可以指定在何种情况下应该或不应该遵循重定向。

Jar:
用于存储 HTTP Cookie。如果设置了此字段,客户端将能够处理 Cookie,例如在请求之间保持会话状态。

Do 方法:
Do 方法是 http.Client 结构体中最重要的方法之一。它接收一个 *http.Request 对象作为参数,发送请求,并返回一个 *http.Response 对象和一个 error 值。

client := http.DefaultClient
resp, err := client.Do(req)

这个代码就是创建一个客户端,然后调这个客户端的DO方法发送请求,参数就刚刚构造的请求.
返回值就是服务器的响应,拿到这个结构体里面的body字段就可以度响应体的内容了,这里注意读完记得调用body的close方法关闭数据流.

fmt.Println(resp.Status)

这个是打印响应的状态码.


再来看一个实例:
以下是一个使用请求头的实例,该实例通过设置请求头,来实现使用Basic认证机制访问API

package main

import (
    "fmt"
    "net/http"
    "encoding/base64"
)

func main() {
    username := "your_username"
    password := "your_password"
    url := "https://api.example.com"

    // 创建HTTP客户端
    client := &http.Client{}

    // 创建请求
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        panic(err)
    }

    // 添加Basic认证头
    auth := username + ":" + password
    basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
    req.Header.Add("Authorization", basicAuth)

    // 发送请求
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    // 处理响应
    fmt.Println(resp.Status)
}

解读:
功能:实现了一个简单的HTTP客户端,用于发送一个带有基本认证(Basic Authentication)的GET请求到指定的URL

encoding/base64:这个包是用来处理base64编码的,你只需要知道这个在HTTP基本认证中非常有用就行了.

username := “your_username”
password := “your_password”
url := “https://api.example.com”
这个是定义用于HTTP基本认证的用户名和密码,以及要请求的URL.

client := &http.Client{}
这个在上个例子也说了,创建一个HTTP客户端,(结构体实例化)

req, err := http.NewRequest(“GET”, url, nil)创建HTTP GET请求

auth := username + “:” + password
basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
req.Header.Add(“Authorization”, basicAuth)
这个是添加基本的认证头
将username和password通过:连接起来,然后对其进行base64编码,然后假设"Basic"这个前缀.
然后添加到创建的请求的头部的Authorization字段.

resp, err := client.Do(req)然后调用这个Do方法就是进行请求的发送了.resp就是服务器对请求的响应.

fmt.Println(resp.Status) 这里是打印响应的状态码.

最后一个补充:
什么是认证头?什么是基本认证?
认证头:是HTTP请求中的一个头部字段,用于包含用户认证信息,以便于HTTP服务端验证请求发送者的身份,这个头部字段在许多需要安全认证的HTTP通信中很重要.
基本认证:这个例子中使用到的就是HTTP基本认证,这是一种简单的认证方式,它的工作原理如下:
1.用户和密码的组合,用户和密码用:连接形成一个字符串,比如 “username:password”
2.Base64编码,这个字符串要转成base64编码,base64是一种用64个字符表示任意二进制数据的方法
3.构建认证头:编码后的字符串前加上 "Basic " 前缀,构成完整的认证头的值。例如,如果 “username:password” Base64 编码后是 “dXNlcm5hbWU6cGFzc3dvcmQ=”,那么认证头的值就是 “Basic dXNlcm5hbWU6cGFzc3dvcmQ=”
4.添加到HTTP请求头.,上面构建的这个完整的值被设置到http请求的Authorization头部字段中.一半是不建议单独使用基本认证进行敏感信息的传输,因为base64非常容易被解码.实际的应用场景中应该采用更安全的认证方法.


golangheader内容类型和字符编码

在Go语言中,我们可以使用http包中的Header类型来设置和获取请求头信息。其中,Content-Type和Content-Encoding头可以用于指定请求正文的类型和编码。下面是一些常见的Content-Type和Content-Encoding类型:
1.Content-Type:
text/plain: 纯文本格式
text/html: HTML格式
application/json: JSON格式
application/xml: XML格式
application/pdf: PDF格式
image/jpeg: JPEG图片格式
image/png: PNG图片格式
multipart/form-data: 文件上传格式
调用header类型的Set()方法就可以设置Content-Type
比如

func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    // ...
}

在基于net/http包的web服务器中,这个函数通常称为处理HTTP请求的处理器函数,这样的函数用来响应特定的HTTP请求.

w是用于向客户端发送响应的接口,我可以通过这个接口设置响应的状态码,请求头,以及写入响应体.

r表示接收到的客户端请求,它包含了请求的各种信息,请求里面那些字段.

可能这么说有点抽象,还是不太懂这个函数具体干了啥,处理了什么.下面是进一步解读:
这个handler函数是在服务器定义的,用于响应客户端的HTTP请求,然后这个函数中,通过设置Content-Type 响应头为 “application/json”,服务器告诉客户端它返回的响应体是Json格式的数据,这意味着客户端接收到这个响应时,应该按照Json格式来解析响应体.

总的来说,这是告知客户端如何解析响应数据的一种方式,而客户端请求的格式则时由客户端决定,并且需要服务器端能够相应的处理.

Content-Encoding:
gzip: Gzip压缩格式
deflate: Deflate压缩格式
br: Brotli压缩格式
还是使用Set方法来设置请求头中的这个字段:

func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Encoding", "gzip")
    // ...
}

这个函数就是在服务器端设置相应的内容编码为gzip,客户端收到这个响应后,可以根据这个头部来正确的解压缩和解析响应体.


http请求头缓存和过期应用

HTTP请求头中的缓存和过期机制时为了优化网络性能和提高用户体验而设计的,常用于浏览器和服务器之间的通信,下面是HTTP请求头中的缓存和过期相关的一些常用字段和性质
1.Cache-Control:缓存控制字段,用于控制缓存的行为。常见的取值包括:
max-age=:指定缓存的最大存活时间,单位为秒。
no-cache:表示需要重新验证缓存,不使用本地缓存。
no-store:表示不缓存任何内容。
public:表示可以缓存响应,包括客户端和代理服务器。
private:表示只能客户端缓存响应,不能被代理服务器缓存。

2.Expires:缓存过期时间字段,用于指定缓存的过期时间。它的值是一个HTTP日期格式的时间字符串,例如"Sun, 17 Mar 2024 12:34:56 GMT"。如果指定了Expires字段,则缓存将在该时间点之后过期。

3.Last-Modified:最后修改时间字段,用于指定响应内容的最后修改时间。它的值是一个HTTP日期格式的时间字符串,例如"Sun, 17 Mar 2024 12:34:56 GMT"。如果服务器支持条件请求,浏览器可以通过发送If-Modified-Since字段来验证缓存是否过期,从而避免重复下载内容

4.ETag:实体标识字段,用于指定响应内容的实体标识。它的值是一个字符串,用于表示响应内容的特定版本。如果服务器支持条件请求,浏览器可以通过发送If-None-Match字段来验证缓存是否过期,从而避免重复下载内容。

实例:
简单演示如何使用HTTP请求头中的缓存和过期机制

package main

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

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// 设置响应头
		w.Header().Set("Cache-Control", "max-age=60") // 设置缓存时间为60秒
		w.Header().Set("Expires", time.Now().Add(time.Minute).UTC().Format(http.TimeFormat)) // 设置过期时间为1分钟后
		w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) // 设置最后修改时间为当前时间

		// 如果客户端发送了If-Modified-Since字段,则验证缓存是否过期
		if ifModifiedSince := r.Header.Get("If-Modified-Since"); if ifModifiedSince != "" {
			lastModified, err := time.Parse(http.TimeFormat, ifModifiedSince)
			if err == nil && lastModified.UTC().Add(time.Minute).After(time.Now().UTC()) {
				w.WriteHeader(http.StatusNotModified) // 返回304状态码表示内容未修改
				return
			}
		}

		// 返回内容
		fmt.Fprintf(w, "Hello, world!")
	})

	http.ListenAndServe(":8080", nil)
}

这个实例创建了一个HTTP处理函数,设置了响应头中的缓存控制,过期时间,和最后修改时间.
r表示接收到的客户端的请求,这里之间去检查它的If-Modified-Since字段,验证缓存是否过期,如果未过期,就返回304状态码表示内容未修改,否则返回新的内容,这样就有效的时间了HTTP请求头中的缓存和过期机制,减少网络传输的数据量,提高页面的加载速度和用户体验.


golang 请求头跨域请求应用

什么是跨域请求?
跨域请求是指浏览器在向一个源(域名,协议,端口号组合)发送请求时,请求的目标资源所在的域名与当前页面所在的页面不一致,即跨域请求,通常情况下,浏览器会限制跨域请求,以保证用户安全.
举例:
例如,假设当前页面的地址是http://example.com,而要请求的资源地址是
http://api.example.net/data,由于域名不同,这就是一个跨域请求。

通常跨域请求会受到浏览器的限制,但可以通过设置响应头中的Access-Control-Allow-*字段来支持跨域请求.在服务端设置允许跨域请求的响应头后,浏览器就可以发送跨域请求并获取响应了.

来看实例

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// 设置响应头,允许跨域请求
		w.Header().Set("Access-Control-Allow-Origin", "*") // 允许所有域名访问
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") // 允许的HTTP方法
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") // 允许的HTTP请求头

		// 处理跨域请求
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusOK) // 返回200状态码表示预检请求成功
			return
		}

		// 返回内容
		fmt.Fprintf(w, "Hello, world!")
	})

	http.ListenAndServe(":8080", nil)
}

在这个示例中,服务器创建了一个http处理函数,设置了响应头中的Access-Control-Allow-*字段,允许跨域访问,如果客户端发送了OPTIONS请求,则返回200状态码表示预检请求成功,否则之间返回内容,通过这种设置响应头字段的形式实现了跨域请求.


http请求头用户代理应用

在HTTP请求头中,用户代理(User-Agent)字段用于表示客户端访问网站时使用的浏览器类型,版本,操作系统等信息,以便服务器根据客户端的特性做出相应的相应.在Golang中,可以通过HTTP请求头中的User-Agent字段来识别客户端类型,从而做出针对性的相应.

实例:演示如何在Golang中读取HTTP请求头中的User-Agent字段

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		userAgent := r.Header.Get("User-Agent")
		fmt.Printf("User-Agent: %s\n", userAgent)

		// 根据不同的User-Agent字段做出相应的响应
		if userAgent == "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36" {
			fmt.Fprintf(w, "Hello, Chrome user!")
		} else if userAgent == "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0" {
			fmt.Fprintf(w, "Hello, Firefox user!")
		} else {
			fmt.Fprintf(w, "Hello, unknown user!")
		}
	})

	http.ListenAndServe(":8080", nil)
}

通过r的header的get方法就可以得到了User-Agent字段的内容,然后根据这个用户代理的内容作相应的处理就可以了,这就达到了针对不同用户代理采取针对性操作的目的.

在本例中:创建了一个HTTP处理函数,读取了HTTP请求头中的User-Agent字段,根据不同的User-Agent字段做出相应的响应.


Golang响应头

实例1:处理http响应头

package main

import (
    "fmt"
    "net/http"
)

func main() {
    resp, err := http.Get("https://example.com")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println(resp.Status)

    header := resp.Header
    fmt.Println(header.Get("Content-Type"))
}

通过GET函数向这个地址发了一个Get请求,然后打印这个响应的状态码,然后通过返回的resp.Header获取相应头,并通过header.Get函数得到响应头里这个字段的值.
需要注意的是,在处理响应头时,应该注意防止注入攻击,

实例2:
以下是一个使用响应头的示例,该示例通过设置Conten-Dispositon头来实现文件下载.

package main

import (
    "fmt"
    "net/http"
    "os"
)

func downloadHandler(w http.ResponseWriter, r *http.Request) {
    // 获取文件名
    filename := "example.pdf"

    // 打开文件
    file, err := os.Open(filename)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        fmt.Fprintf(w, "Error: %s", err.Error())
        return
    }
    defer file.Close()

    // 设置响应头
    w.Header().Set("Content-Type", "application/pdf")
    w.Header().Set("Content-Disposition", "attachment; filename="+filename)

    // 写入响应体
    _, err = io.Copy(w, file)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        fmt.Fprintf(w, "Error: %s", err.Error())
    }
}

func main() {
    http.HandleFunc("/download", downloadHandler)
    http.ListenAndServe(":8080", nil)
}

创建了一个/download的路由,当客户端请求该路由时,服务器会将example.pdf作为响应体发送给客户端,并通过设置Content-Disposition头,告诉客户端将响应体保存为一个附件并下载.

详细解读:
先大体来说每个函数完成了什么功能
downloadHandle,这个函数用于处理HTTP请求和下载文件
filename遍历设置了要下载的文件名为example.pdf
然后用os.Open打开文件,如果打开这个文件有错误(文件不存在),那么就会返回HTTP状态码500,并返回错误信息
w.WriteHeader(http.StatusInternalServerError)这个代码的功能就是向HTTP客户端发送一个HTTP状态码,具体来说时发送了一个内部服务器错误的状态码500.

这里的w是http.ResponseWriter的一个实例,用于构造HTTP响应,这个接口提供了许多方法来发送数据和HTTP头到客户端
WriteHeader(code int)这个方法就是w接口实现的一个方法,用于发送HTTP状态码,code是一个参数是一个整数,表示HTTP状态码.
http.StatusInternalServerError是net/http包的一个常量代表500

http.ResponseWriter解读:
是net/http包的一个接口,用于构建HTTP响应,这个接口在web服务器护理HTTP请求时非常的关键,因为它提供了一系列方法来设置响应的状态码,头部和正文,当一个函数作为HTTP请求的处理器时,通常会接收http.ResponseWriter 和*http.Request作为参数.
这个参数主要提供了以下功能:
1.发送响应头:
使用Header()方法,可以返回一个http.Header类型的值,这是一个映射map,包含响应的头部信息.你可以添加或修改这个映射中的条目来设置响应头.
2.写入响应状态码:
WriteHeader(statusCode int),这个方法用来写入HTTP响应的状态码,例如http.StatusOK这个常量代表状态码200.注意一旦调用了WriterHeader就不能更改状态码,且必须在写入响应正文之前调用.
3.写入响应正文
Write([]byte)方法来写入响应的正文部分,这个方法接收一个字节切片然后将其写入HTTP响应正文.该方法还会自动设置Content-Type响应头(如果未设置)并写入状态码(如果未写入)
在实际使用中,http.ResponseWriter 通常与 *http.Request 一起使用,以处理特定的 HTTP 请求。downloadHandler 函数就使用了 http.ResponseWriter 来构建和发送一个文件下载的响应。这包括设置响应头(如 Content-Type 和 Content-Disposition),发送响应状态码(如出现错误时发送 500),以及写入响应正文(即文件内容)。

Content-Disposition这个字段是响应头里的字段,用于在浏览器接收到响应的时候,告诉浏览器如何处理响应体的内容.具体来说,它可以用来指示浏览器应该显示内容还是将内容作为文件下载.这个字段一般有两种类型:inline和attachment
inline:当Content-Disposition设置为inline时,它表示响应的内容应当被直接在浏览器中显示,而不是提示用户下载,例如这可以用于直接在浏览器打开PDF或图片文件.
attachment:它通常用于告诉浏览器将响应的内容作为文件下载,可以通过这种方式来指定下载文件的默认文件名Content-Disposition: attachment; filename="example.pdf.这意味着当用户访问对于的URL时,服务器的响应会提示浏览器将内容作为名为example.pdf的文件下载,而不是尝试在浏览器窗口中直接打开它.
这种方式常常用在提供文件下载的web应用中,比如文档,音乐,视频或任何类型的文件下载服务.

_, err = io.Copy(w, file)
用这个函数将文件的内容写入了响应体

http.HandleFunc(“/download”, downloadHandler)
解读这个函数:
用于将特定的URL路径映射到一个处理函数,这是创建HTTP服务器时处理请求和响应的一种基本方式

func HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
pattern一个字符串,代表URL的路径模式,/是根路径,/hello表示路径为/hello的请求,handler是一个处理函数,用于处理介绍到的HTTP请求,这个处理函数的参数很重要,有很大的作用.
这个函数放在这个例子里面有啥用:这表示发送到这个路径下的HTTP请求都会被这个处理函数处理.
对于这个函数有个很常用的说法:注册服务,更精确的说就是注册路由处理器,当HTTP服务器接收到一个请求并且请求的路径匹配该模式的时候,就会调用相应的处理函数,这是一种非常常见的模式,用于在go语言编写HTTP服务器中组织和处理路由逻辑.

这种注册机制是构建基于HTTP的服务的基本方法之一

http.ListenAndServe(“:8080”, nil)
这个事启动HTTP服务器监听端口,没有就是本地的.
这个通常也被称为服务启动…

这样这个代码可以完全看得懂了.

你可能感兴趣的:(golang,网络,开发语言)