GO WEB 学习笔记(一)WEB 基础

WEB 工作方式

  • 我们平时上网一般的都是通过浏览器进行上网的,但是我们上网后面的流程究竟是怎么样的?下面我就来简单的简述一下
  1. 首先我们将浏览器叫做客户端,客户端输入网站URL,发出访问的请求,(URL是统一资源定位符,描述一个网络上的资源)
  2. 这个请求会进入到DNS服务器 ,DNS会根据网址URL找出这个网址所在服务器的IP,(DNS域名系统)
  3. 客户端通过这个IP跟服务器建立TCP连接,然后将HTTP Request请求发过去
  4. 服务器接收到客户端的Request请求包之后,才开始进行处理,然后将http中的response请求包返回
  5. 客户端接收到所有的response请求包之后,随后断开与该服务器之间的TCP请求,将数据进行渲染,呈现给客户

在这里插入图片描述

  • 下面我们了解一下DNS解析的过程
  1. 在浏览器中输入一个网址,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析
  2. 如果hosts没有这个域名映射,就会查找本地的DNS解析器缓存,是否与这个网址映射关系,如果有,直接返回,完成域名解析
  3. 如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,首先会找TCP/IPD参数中设置的首选DNS服务器,在此我们叫它本地DNS服务器,此服务器收到查询时,如果要查询的域名包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。
  4. 如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性
  5. 如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地DNS服务器的设置进行查询,如果未用转发模式,本地DNS就把请求发至"根DNS服务器",根DNS服务器收到请求后会判断这个域名是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负责这个域的服务器,服务器收到请求后,如果自己无法解析就会给下一级服务器地址进行解析,重复这个操作,直至找到这个网址的主机
  6. 如果用的是转发模式,此DNS服务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析,上一级服务器如果不能解析,就把请求转至上上级,以此循环。
  • HTTP 协议:根据上面DNS的步骤,我们获取的只是IP地址,但是服务器与客户端的交互还需要一个预定俗称的协议才行,这样才能保证安全与规范,可以让全世界通用,而这个协议就是HTTP协议,HTTP协议是一种让WEB服务器与浏览器发送与解手数据的协议,建立在TCP协议上,一般采用TCP的 80端口。
  1. HTTP协议定义了很多与服务器交互的请求方法,最基本的有4种,分别是GET,POST,PUT,DELETE。一个URL地址用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,Delete就对应着这个资源的查,改,增,删4个操作。
    • get 与 post 的区别:
      • get 提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,post方法就是把提交数据放在HTTP包的Body中。
      • get提交的数据大小有限制,post没有限制
      • get提交数据,会带来安全问题,post会做保密
  2. HTTP 请求包:分为三部分
    • Request line 请求行
    • Request header 请求头
    • body 主体
  3. HTTP 响应包:
    • 状态行:本号,状态码,状态消息
      • 状态码:
        • 1xx:提示信息–表示请求已被成功接收,继续处理
        • 2xx:成功–表示请求已被成功接收,理解,接受
        • 3xx:重定向–要完成请求必须进行更进一步的处理
        • 4xx:客户端错误–请求有语法错误或请求无法实现
        • 5xx:服务器端错误–服务器未能实现合法的请求
    • 服务器使用的WEB软件名及版本
    • 发送时间
    • 服务器发送信息的类型
    • 表示发送HTTP包是分段发的
    • 保持连接状态
    • 主体内容长度
    • 消息体

GO 语言搭建一个web服务器

  • go语言提供了一个完善的net/http包,通过http包可以很方便的搭建一个可以运行的web服务。下面是例子:
package main

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

func getWeb(w http.ResponseWriter, r *http.Request) {
	//解析参数,默认是不会解析
	r.ParseForm()

	//打印信息
	fmt.Println(r.Form)
	fmt.Println("Path:", r.URL.Path)
	fmt.Println("scheme:", r.URL.Scheme)
	for k, v := range r.Form {
		fmt.Println("Key:", k, "Value:", v)
	}
	fmt.Fprintf(w, "hello world!")
}

func main() {
	http.HandleFunc("/", getWeb)
	err := http.ListenAndServe(":9090", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

在这里插入图片描述
在这里插入图片描述

  • 由上面的例子可以知道,web服务器的编写很简单,只需要调用HTTP的两个函数即可,并且这么方便便捷的代码不仅能运行一个web服务器,还能支持高并发特性。

GO语言如何使WEB工作

  • GO语言实现Web服务的工作模式:
    在这里插入图片描述
  1. 创建 Listen Socket,监听指定的端口,等待客户端请求到来
  2. Listen Socket 接受客户端的请求,得到Client Socket,接下来通过Client Socket与客户端通信
  3. 处理客户端的请求,首先从Client Socket读取HTTP请求的协议头,如果是POST方法,还可能要读取客户端提交的数据,然后交给相应的handler处理请求,handler处理完毕准备好客户需要的数据,通过Client Socket写给客户端
  • 知道了web服务器的工作模式,还有三个问题,go语言是如何监听端口的,如何接受客户端请求,如何分配handler?
    在这里插入图片描述
  1. 通过ListenAndServer来监听,底层是这样的
    • 初始化一个server对象
    • 调用net.listen,用 tcp协议 搭建一个服务
    • 监控我们设置的端口
  2. 调用srv,Serve 函数,来接受客户端的请求信息。底层起了一个for{}
    • 首先通过Listener接收请求
    • 创建一个conn
    • 单独打开一个goroutine,用来服务conn
    • 用户每次请求都会开启一个新的 goroutine 去服务
  3. 对于具体分配到相应的函数来处理请求
    • conn首先会解析 request:c.readRequest()
    • 获取相应的handler:handler := c.server.Handler,也就是调用ListenAndServe函数的第二参数

GO 语言的HTTP包详解

  • Go语言的http有两个核心功能:conn和ServeMax
  1. Conn 的 goroutine:
    • goroutines处理Conn的读写事件,这样每个请求都能保持独立,相互不阻塞,以高效响应网络事件。
    • 下图代码就是客户端每次请求都会创建一个conn,这个conn保存了这次请求的信息,然后传递给相对应的handler,以保证每次请求的独立性
      在这里插入图片描述
  2. ServeMux:conn.Server内部调用了http包默认的路由器,通过路由器把本次请求的信息传递到了后端处理函数。但是这个路由器是怎么实现的呢?下面来看一下,ServeMux的机构:
    在这里插入图片描述
    • 其中muxEntry时路由规划,一个string对应一个mux实体,里的string就是注册路由的表达式
      在这里插入图片描述
    • 其中handler就是这个路由表达式对应的路由,这是一个接口,还记得我们之前定义的getWeb这个函数吗,他没有实现ServeHTTP这个接口为啥可以被当作handler调用呢?
      在这里插入图片描述
      * 答案是,因为HandlerFunc这个函数,这个函数调用之后,类型就会默认实现这个ServeHTTP这个接口,这样就会拥有ServeHTTP方法
      在这里插入图片描述
    • 路由器里面存储好了相应的路由规则之后,是怎么分发的呢?路由器接收到请求之后调用mux.handler®.ServeHTTP(w, r),也就是调用对应路由的handler的ServerHTTP接口,根据用户请求的URL和路由器里面存储的map去匹配的,当匹配到之后返回存储的handler,调用这个handler的ServHTTP接口就可以执行到相应的函数了。
      在这里插入图片描述

Go语言代码的执行流程

  1. 首先调用Http.HandleFunc
    • 调用了 DefaultServerMux 的 HandleFunc
    • 调用了DefaultServerMux 的 Handle
    • 在 DefaultServeMux 的 map[string]muxEntry 中增加对应的handler和路由规则
  2. 调用http.ListenAndServe(“:9090”,nil)
    • 实例化Server。
    • 调用Server的ListenAndServe()。
    • 调用net.Listen(“tcp”, addr)监听端口。
    • 启动一个for循环,在循环体中Accept请求。
    • 对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务go c.serve()。
    • 读取每个请求的内容w, err := c.readRequest()。
    • 判断handler是否为空,如果没有设置handler(这个例子就没有设置handler),handler就设置为DefaultServeMux。
    • 调用handler的ServeHttp。
    • 在这个例子中,下面就进入到DefaultServerMux.ServeHttp。
    • 根据request选择handler,并且进入到这个handler的ServeHTTP,
    • 选择handler:
      • 判断是否有路由能满足这个request(循环遍历ServerMux的muxEntry)。
      • 如果有路由满足,调用这个路由handler的ServeHttp。
      • 如果没有路由满足,调用NotFoundHandler的ServeHttp。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值