快速体验Go启动一个web服务器

696 阅读4分钟

这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战

HTTP协议详解

HTTP 超文本传输协议 (HTTP-Hypertext transfer protocol),是一个属于应用层的 面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于 1990 年提出,经过几年的使用与发展,得到不断地完善和扩展。它是一种详细规定了浏览器万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。 客户端与服务端通信时传输的内容我们称之为报文.

HTTP 就是一个通信规则,这个规则规定了客户端发送给服务器的报文格式,也规定了服务器响应给客户端的报文格式。实际我们要学习的就是这两种报文。客户端发送给服务器的称为”请求报文“,服务器发响应给客户端的称为”响应报文“。

HTTP协议是Web工作的核心,所以要了解清楚Web的工作方式就需要详细的了解清楚HTTP是怎么样工作的。

HTTP是一种让Web服务器浏览器(客户端) 通过Internet发送接收数据的协议,它建立在TCP协议之上,一般采用TCP80端口。它是一个请求、响应协议--客户端发出一个请求,服务器响应这个请求。在HTTP中,客户端总是通过建立一个连接与发送一个HTTP请求来发起一个事务。服务器不能主动去与客户端联系,也不能给客户端发出一个回调连接。客户端与服务器端都可以提前中断一个连接。例如,当浏览器下载一个文件时,你可以通过点击“停止”键来中断文件的下载,关闭与服务器的HTTP连接。

HTTP协议是无状态的,同一个客户端的这次请求和上次请求是没有对应关系的,对HTTP服务器来说,它并不知道这两个请求是否来自同一个客户端。为了解决这个问题, Web程序引入了Cookie机制来维护连接的可持续状态。

HTTP协议是建立在TCP协议之上的,因此TCP攻击一样会影响HTTP的通讯,例如比较常见的一些攻击:SYN Flood是当前最流行的DoS(拒绝服务攻击)与DdoS(分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式。

HTTP 协议的会话方式

浏览器与 WEB 服务器的连接过程是短暂的,每次连接只处理一个请求和响应。对每一 个页面的访问,浏览器与 WEB 服务器都要建立一次单独的连接。 

浏览器到 WEB 服务器之间的所有通讯都是完全独立分开的请求和响应对。

Go语言里面提供了一个完善的net/http包,通过http包可以很方便的搭建起来一个可以运行的Web服务。同时使用这个包能很简单地对Web的路由,静态文件,模版,cookie等数据进行设置和操作。

http包建立Web服务器

package main

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

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()  //解析参数,默认是不会解析的
	fmt.Println(r.Form)  //这些信息是输出到服务器端的打印信息
	fmt.Println("path", r.URL.Path)
	fmt.Println("scheme", r.URL.Scheme)
	fmt.Println(r.Form["url_long"])
	for k, v := range r.Form {
		fmt.Println("key:", k)
		fmt.Println("val:", strings.Join(v, ""))
	}
	fmt.Fprintf(w, "Hello afei!") //这个写入到w的是输出到客户端的
}

func main() {
	http.HandleFunc("/", sayhelloName) //设置访问的路由
	err := http.ListenAndServe(":9090", nil) //设置监听的端口
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

上面这个代码,我们build之后,然后执行web.exe,这个时候其实已经在9090端口监听http链接请求了。

在浏览器输入http://localhost:9090

可以看到浏览器页面输出了Hello afei!

可以换一个地址试试:http://localhost:9090/?url_long=111&url_long=222

我们看到上面的代码,要编写一个Web服务器很简单,只要调用http包的两个函数就可以了

  package main
    import (
        "fmt"
        "log"
        "net/http"
        "strings"
    )

    func quickWeb(w http.ResponseWriter,r *http.Request) {
        fmt.Fprintf(w,"helo afei.")
    }

    func main() {
        http.HandleFunc("/quickWeb", quickWeb) //设置访问的路由
        err := http.ListenAndServe(":8080", nil) //设置监听的端口
        if err != nil {
            log.Fatal("ListenAndServe: ", err)
        }
    }