主要介绍web和http协议。

1. Web简介

1.1 什么是web

严格来说,Web分为Web应用Web服务。Web 应用应该是:它会对客户端发送的 HTTP 请求做出响应,并通过 HTTP 响应将 HTML 回传至客户端。

一个Web应用至少需要两个条件:

  • 这个程序必须向发送命令请求的客户端返回 HTML,而客户端则会向用户展示渲染后的 HTML
  • 这个程序在向客户端传送数据时必需使用 HTTP 协议

在这个定义的基础上,如果一个程序不是向用户渲染并展示HTML,而是向其他程序返回某 种非 HTML 格式的数据,那么这个程序就是一个为其他程序提供服务的 Web 服务

1.2 Web的基本原理

我们平时使用的浏览器本身就是一个客户端,平时的上网过程是:

  1. 输入URL时,浏览器回去请求DNS服务器。DNS服务器返回相应的域名对应的IP
  2. 浏览器通过IP寻址找到对应的服务器,要求建立TCP连接。
  3. 随后浏览器发送HTTP请求包。
  4. 服务器收到后,返回HTTP响应包。
  5. 浏览器接收并渲染响应包。
  6. 全部完成后,与服务器断开TCP连接

那么Web的工作原理可以被归纳为4个方面:

  • TCP/IP协议建立的TCP连接
  • 客户端发送HTTP协议请求包
  • 服务器发送HTTP协议响应包
  • 客户端解释HTML文档,在屏幕上渲染结果。

1.3 URL和DNS解析

URL (Uniform Resource Locator) 是 统一资源定位符 的英文缩写,用于描述一个网络上的资源,基本格式如下

scheme://host[:port#]/path/.../[?query-string][#anchor]
scheme         方案,指定底层使用的协议(例如:http, https, ftp)
host           HTTP 服务器的 IP 地址或者域名
port#          HTTP 服务器的默认端口是 80,这种情况下端口号可以省略。如果使用了别的端口,必须指明,例如 http://www.cnblogs.com:8080/
path           访问资源的路径
query-string   发送给 http 服务器的数据
anchor         锚

DNS (Domain Name System) 是 域名系统 的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,它用于 TCP/IP 网络,它从事将主机名或域名转换为实际 IP 地址的工作,类似于翻译官

DNS查询时优先考虑本地的Host文件本地的DNS解析器是否保留有缓存映射,如果没有就向上一级请求。依次按照DNS根服务器,DNS顶层服务器,DNS管理方服务器的顺序请求。

所谓递归查询就是变更查询者,迭代查询则没有变更:这个例子中查询者由客户端变味了本地DNS服务器,所以是递归查询。

2. HTTP

2.1 什么是HTTP

HTTP是OSI的应用层协议,Web页面中的所有数据通过这个协议传输。

HTTP 是一种无状态由文本构成请求,响应( request-response )协议,这种协议使用的是客户端-服务器( client-server )模型

无状态协议的意思是:服务器唯一知道的就是客户端会向服务器发送请求,而服务器则会向客户端返回响应,并且后续发生的请求对之前发生过的请求一无所知。 其他协议,比如FTP和Telnet这类面向连接的协议则会在客户端和服务器之间创建一个持续存在的通信通道。

另外一点,HTTP也是以纯文本方式而不是二进制方式发送和接收协议数据的。这样做是为了让开发者可以在元需使用专门的协议分析工具的情况下,弄清楚通信中正在发生的事情,从而更容易进行故障排查。

2.2 HTTP请求

前面提到,HTTP是一个请求-响应协议,协议涉及的所有事情都从一个请求开始

格式构成是:

  • 一个请求行request-line
  • 头部header
  • 一个空行
  • 报文主体body

比如,其中Get就是请求方法,之后是URI(Uniform Resource Identifier),以及HTTP版本。

GET /Protocols/rfc2616/ rfc2616.ht ml HTTP/ 1.1 
Host : www.w3.org 
User-Agent : Mozilla/5.0 

<!DOCTYPE html PUBLIC ”-//W3C//DTD XHTML 1.0 Strict//EN”

在HTTP协议中定义了许多请求方法:

  • GET 命令服务器返回指定的资源
  • HEAD 与 GET 方法的作用类似,唯一的不同在于这个方法不要求服务器返回报文的主体。只取得头部。
  • PUT 命令服务器将报文主体中的数据设置为 URI 指定的资源。
  • DELETE 命令服务器删除 URI 指定的资源
  • TRACE 命令服务器返回请求本身。 通过这个方法,客户端可以知道介于它和服务器 之间的其他服务器是如何处理请求的。
  • OPTIONS 一命令服务器返回它支持的 HTTP 方法列表
  • CONNECT 命令服务器与客户端建立一个网络连接
  • PATCH 命令服务器使用报文主体中的数据对 URI 指定的资源进行修改。

2.3 HTTP响应

HTTP 响应报文是对 HTTP 请求报文的回复。 跟 HTTP 请求一样, HTTP 响应也是由一系列 文本行组成的,其中包括:

  • 一个状态行
  • 响应头部
  • 一个空行
  • 一个可选的报文主体

HTTP 响应的组织方式跟 HTTP 请求的组织方式是完全相同的。

200 OK 
Date : Sat, 22 Nov 2014 12 : 58:58 GMT 
Server: Apache/2 
    Last-Modified: Thu, 28 Aug 2014 21:01:33 GMT 
Content-Length: 33115 
Content-Type: text/html; charset=iso-8859- 1

<!DOCTYPE html PUBLIC ”-//W3C//DTD XHTML 1.0 Strict//EN” ”http://www.w3.org/ TR/xhtmll/DTD/xhtmll-strict.dtd” > <html xmlns= ’ http: //www.w3 . org/1999/ xhtml ’ > <head><title>Hypertext Transfer Protocol -- HTTP/1 .1</title></ head><body> ... </body></html>

首行包含了状态码,共计5种类型:

3. 使用go编写一个web程序

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 world!") // 这个写入到 w 的是输出到客户端的
}

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

当我们在浏览器输入http://localhost:9090后就可以看到Hello World,并在服务器窗口看到:

map[]
path /
scheme 
[]
map[]
path /favicon.ico
scheme 
[]

如果输入http://localhost:9090/?url_long=111&url_long=222,(问号用于分割URL和传输数据)得到的结果是:

map[url_long:[111 222]]
path /
scheme 
[111 222]
key: url_long
val: 111222
map[]
path /favicon.ico
scheme 
[]