一、web编程基础

1.1 web工作方式

1.2 HTTP协议详解

a、http 请求包体

GET /domains/example/ HTTP/1.1 //请求行: 请求方法 请求URI HTTP协议/协议版本

Host:www.iana.org //服务端的主机名

User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko)

Chrome/22.0.1229.94 Safari/537.4 //浏览器信息

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 //客户

端能接收的MIME

Accept-Encoding:gzip,deflate,sdch //是否支持流压缩

Accept-Charset:UTF-8,*;q=0.5 //客户端字符编码集

//空行,用于分割请求头和消息体

//消息体,请求资源参数,例如POST传递的参数

b、http 响应包体

HTTP/1.1 200 OK //状态行

Server: nginx/1.0.8 //服务器使用的WEB软件名及版本

Date:Date: Tue, 30 Oct 2012 04:14:25 GMT //发送时间

Content-Type: text/html //服务器发送信息的类型

Transfer-Encoding: chunked //表示发送HTTP包是分段发的

Connection: keep-alive //保持连接状态

Content-Length: 90 //主体内容长度

//空行 用来分割消息头和主体

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... //消息体

1.3 http Keep-Alive特性

A. Keep-Alive用来保持连接

B. Keep-Alive通过web服务器(nginx、httpd)进行设置,保持的时间

1.4 web程序开发

A. 标准包 “net/http”封装web服务相关功能

B. 使用简单、性能媲美nginx。

实例:

package main

import (
"fmt"
"log"
"net/http"
"strings"
) func sayhelloName(w http.ResponseWriter, r *http.Request) { //第一个参数是一个接口,第二个参数是一个结构体(封装了一系列方法,比如:取post提交参数等),r是接受请求,w是返回给浏览器
r.ParseForm() //解析参数,默认是不会解析的,如果是post请求(带表单参数),会进行解析
fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息,将表单打印出来
fmt.Println("path", r.URL.Path) //请求路径
fmt.Println("scheme", r.URL.Scheme) //scheme是http还是https
fmt.Println(r.Form["url_long"]) //传递了一个表单参数url_long
for k, v := range r.Form {
fmt.Println("key:", k)
fmt.Println("val:", strings.Join(v, ""))
}
fmt.Fprintf(w, "Hello world!") //这个写入到w的是输出到客户端的
//w这里是一个接口,接口的好处就体现在封装成一个接口的话,不论是返回文件或者图片或者html都可以通过接口进行返回,不用接口的话,你需要为每一种返回类型写函数。帮你更好理解 }
func main() {
http.HandleFunc("/", sayhelloName) //设置访问的路由,sayhelloName是函数类型的参数
err := http.ListenAndServe(":9090", nil) //设置监听的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

执行结果:

浏览器端:

实例:获取用户传递过来的参数

package main

import (
"fmt"
"net/http"
) func greet(w http.ResponseWriter, r *http.Request) {
word := r.FormValue("word") //通过formvalue来获取用户传递过来参数
fmt.Fprintf(w, "greet Hello World! word:%s", word)
} func main() {
http.HandleFunc("/index", greet)
http.ListenAndServe(":8080", nil)
}

执行结果:

浏览器端:

1.5 Golang web服务工作方式

图1:

go底层源码就是我们上面图示的体现:

绑定监听端口:

进入服务阶段(死循环,所以不停服务):

客户端来一个请求连接,就accept起一个,完了最后通过起一个协程来处理当前连接的这个请求。

go语言里面网络编程模型很简单,就是过来一个连接,起一个goroutine去处理这个连接请求。如果是nginx、c++、c等就需要做一个异步的epoll处理模型,go就非常简单,源码就和上面一样,所以以后要写一个tcp服务器,将上面源码搬过去就可以用。

图2为图1的精细化展示:

二、表单提交

A. html代码中通过<form> </form>括起来的区域,允许用户提交数据。

B.  Go对于表单处理非常方便

实例:

目录结构:

login.html:

<html>
<body>
<form action="/user/login" method="POST">
<div>
<span>用户名:</span><input name="username" >
</div>
<div>
<span>密码:</span><input name="password" >
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>

login.html

main.go

package main

import (
"fmt"
"io/ioutil"
"log"
"net/http"
) func userLogin(w http.ResponseWriter, r *http.Request) {
fmt.Printf("r.method:%s\n", r.Method)
if r.Method == "GET" { //如果是get直接返回请求页面
data, err := ioutil.ReadFile("./login.html")
if err != nil {
http.Redirect(w, r, "/404.html", http.StatusNotFound)
return
} w.Write(data) //要把内容输出到浏览器
} else if r.Method == "POST" {
r.ParseForm() //解析表单
username := r.FormValue("username") //和html文件要一一对应
password := r.FormValue("password") if username == "admin" && password == "admin" {
fmt.Fprintf(w, "login success")
} else {
fmt.Fprintf(w, "login failed")
}
}
} func main() {
http.HandleFunc("/user/login", userLogin)
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

执行结果:

浏览器进行测试:

输入正确:

输入错误:

三、模板介绍与使用

3.1 模板替换

A. {{}}(模板变量)来包含需要在渲染时被替换的字段, {{.}}表示当前的对象(go源码传递过来的对象)。

B. 通过{{.FieldName}}访问对象的属性。

实例:

目录结构:

index.html

<html>
<body>
<form action="/user/login" method="POST">
<div>
<span>用户名:{{.Name}}</span>
</div>
<div>
<span>年龄:{{.Age}}</span>
</div>
</form>
</body>
</html>

index.html

main.go

package main

import (
"fmt"
"html/template" //加载模板的包
"net/http"
) var (
t *template.Template //定义一个接收模板的全局变量
) type User struct {
Name string
Age int
} func initTemplate() (err error) {
t, err = template.ParseFiles("./index.html") //把模板加载进来 ,t是返回的实例
if err != nil {
fmt.Printf("load template failed,err:%v\n", err)
return
}
return
} func handleUserInfo(w http.ResponseWriter, r *http.Request) {
var user User = User{ //初始化 //可以传递任何类型的数据进去
Name: "user01",
Age: ,
} t.Execute(w, user) //进行渲染,t对应的就是模板中的.
} func main() { err := initTemplate()
if err != nil {
return
} http.HandleFunc("/user/info", handleUserInfo)
err = http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Printf("listen failed, err:%v\n", err)
return
}
}

执行结果:

浏览器端:

3.2 if判断

比如说一个场景,大于18岁就弹出来一个红色图标,小于18岁就弹出一个灰色图标,我们就可以通过if判断来实现。

模板:

<html>
</head>
</head>
<body>
{{if gt .Age 18}}
<p>hello, old man, {{.Name}}</p>
{{else}}
<p>hello,young man, {{.Name}}</p>
{{end}}
</body>
</html>

其它用法:

1) not 非
{{if not .condition}}
{{end}}
2) and 与
{{if and .condition1 .condition2}}
{{end}}
3) or 或
{{if or .condition1 .condition2}}
{{end}}
4) eq 等于
{{if eq .var1 .var2}}
{{end}}
5) ne 不等于
{{if ne .var1 .var2}}
{{end}}
6) lt 小于 (less than)
{{if lt .var1 .var2}}
{{end}}
7) le 小于等于
{{if le .var1 .var2}}
{{end}}
8) gt 大于
{{if gt .var1 .var2}}
{{end}}
9) ge 大于等于
{{if ge .var1 .var2}}
{{end}}

实例:

index.html

<html>
<body>
<form action="/user/login" method="POST">
<div>
<span>用户名{{.Name}}</span>
</div>
<div>
<span>年龄:{{.Age}}</span>
</div>
{{if gt .Age 18}}
<div>
<span>hello, old man</span>
</div>
{{else}}
<div>
<span>hello, young man</span>
</div>
{{end}}
</form>
</body>
</html>

index.html

main.go代码依然用的是模板替换的代码

查看结果:

解释:

可以看到年龄小于18,所以传递过来是小于18分支的字符串。

3.3 with语法

当我们传递的是结构体,单层没问题,如果是想调用嵌套结构体的话,就会出问题,此时我们就需要用到with语法。

模板:

<html>
</head>
</head>
<body>
{{with .Name}}
<p>hello, old man, {{.}}</p>
{{end}}
</body>
</html>

解释:

{{.}}:双括号中的点就指的是with后面的变量Name

实例:

结构:

index.html

<html>
<body>
<form action="/user/login" method="POST">
<div>
<span>用户名{{.Name}}</span>
</div>
<div>
<span>年龄:{{.Age}}</span>
</div>
{{if gt .Age 18}}
<div>
<span>hello, old man</span>
</div>
{{else}}
<div>
<span>hello, young man</span>
</div>
{{end}}
{{with .Address}}
<div>
<span>省:{{.Province}}</span>
</div>
<div>
<span>城市:{{.City}}</span>
</div>
<div>
<span>邮编:{{.Code}}</span>
</div>
{{end}}
</form>
</body>
</html>

index.html

main.go

package main

import (
"fmt"
"html/template"
"net/http"
) var (
t *template.Template
) type Address struct {
City string
Province string
Code string
} type User struct {
Name string
Age int
Address Address //继承
} func initTemplate() (err error) {
t, err = template.ParseFiles("./index.html")
if err != nil {
fmt.Printf("load template failed,err:%v\n", err)
return
}
return
} func handleUserInfo(w http.ResponseWriter, r *http.Request) {
var user User = User{ //初始化
Name: "user01",
Age: ,
Address: Address{
City: "beijing",
Province: "beijing",
Code: "",
},
} t.Execute(w, user)
} func main() { err := initTemplate()
if err != nil {
return
} http.HandleFunc("/user/info", handleUserInfo)
err = http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Printf("listen failed, err:%v\n", err)
return
}
}

执行结果:

浏览器端查看:

3.4 循环

传递过来的首先必须要是一个切片

模板:

<html>
<head>
</head>
<body>
{{range .}}
{{if gt .Age 18}}
<p>hello, old man, {{.Name}}</p>
{{else}}
<p>hello,young man, {{.Name}}</p>
{{end}}
{{end}}
</body>
</html>

range . 这个点就是切片中的一个元素

实例:

目录结构:

index.html

<html>
<body>
<form action="/user/login" method="POST">
{{range .}}
<div>
<span>用户名{{.Name}}</span>
</div>
<div>
<span>年龄:{{.Age}}</span>
</div>
{{if gt .Age 18}}
<div>
<span>hello, old man</span>
</div>
{{else}}
<div>
<span>hello, young man</span>
</div>
{{end}}
{{with .Address}}
<div>
<span>省:{{.Province}}</span>
</div>
<div>
<span>城市:{{.City}}</span>
</div>
<div>
<span>邮编:{{.Code}}</span>
</div>
<hr>
{{end}}
{{end}}
</form>
</body>
</html>

index.html

main.go

package main

import (
"fmt"
"html/template"
"net/http"
) var (
t *template.Template
) type Address struct {
City string
Province string
Code string
} type User struct {
Name string
Age int
Address Address
} func initTemplate() (err error) {
t, err = template.ParseFiles("./index.html")
if err != nil {
fmt.Printf("load template failed,err:%v\n", err)
return
}
return
} func handleUserInfo(w http.ResponseWriter, r *http.Request) {
var users []*User
for i := ; i < ; i++ {
var user User = User{
Name: "user01",
Age: ,
Address: Address{
City: "beijing",
Province: "beijing",
Code: "",
},
}
users = append(users, &user)
} t.Execute(w, users) //传递一个切片过去
} func main() { err := initTemplate()
if err != nil {
return
} http.HandleFunc("/user/info", handleUserInfo)
err = http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Printf("listen failed, err:%v\n", err)
return
}
}

执行结果:

浏览器端:

Go语言基础之19--web编程基础的更多相关文章

  1. Web编程基础--HTML、CSS、JavaScript 学习之课程作业“仿360极速浏览器新标签页”

    Web编程基础--HTML.CSS.JavaScript 学习之课程作业"仿360极速浏览器新标签页" 背景: 作为一个中专网站建设出身,之前总是做静态的HTML+CSS+DIV没 ...

  2. Go语言面组合式向对象编程基础总结

    转自:http://blog.csdn.net/yue7603835/article/details/44282823 Go语言的面向对象编程简单而干净,通过非侵入式接口模型,否定了C/C++ Jav ...

  3. Python语言基础07-面向对象编程基础

    本文收录在Python从入门到精通系列文章系列 1. 了解面对对象编程 活在当下的程序员应该都听过"面向对象编程"一词,也经常有人问能不能用一句话解释下什么是"面向对象编 ...

  4. Linux基础篇–shell脚本编程基础

    本章内容概要  编程基础  脚本基本格式  变量  运算  条件测试  配置用户环境 7.1 编程基础程序:指令+数据程序编程风格:   过程式:以指令为中心,数据服务于指令   对象式:以数据为中心 ...

  5. Linux之19——Shell编程基础详解

    第一部分:Linux Shell 简介 Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言. Shell 是指一种应用程序, ...

  6. 【Java基础】Java网络编程基础知识

    什么是网络编程 网络编程是通过使用套接字来达到进程间通信目的,那什么是套接字呢?其实套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的 ...

  7. [置顶] 提高生产力:Web开发基础平台WebCommon的设计和实现

    Web开发中,存在着各种各样的重复性的工作.为了提高开发效率,不在当码农,我在思考和实践如何搭建一个Web开发的基础平台. Web开发基础平台的目标和功能 1.提供一套基础的开发环境,整合了常用的框架 ...

  8. Java入门——(1)Java编程基础

    Java入门--(1)Java编程基础 第二章 Java编程基础   JAVA 代码的基本格式: 修饰符 class 类名{ 程序代码 }   2.1关键字:赋予了特殊含义的单词.   2.2标识符: ...

  9. Java基础教程:网络编程

    Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...

随机推荐

  1. ROS探索总结(四)——简单的机器人仿真

    前边我们已经介绍了ROS的基本情况,以及新手入门ROS的初级教程,现在就要真正的使用ROS进入机器人世界了.接下来我们涉及到的很多例程都是<ROS by Example>这本书的内容,我是 ...

  2. SpringBoot10 整合JSP

    1 整合JSP 1.1 导入相关依赖 JSP依赖.JSTL依赖 <?xml version="1.0" encoding="UTF-8"?> < ...

  3. Realsense深度相机资料

    1.Realsense SDK 2.0 Ubuntu 16.04 安装指导网址 https://github.com/IntelRealSense/librealsense/blob/master/d ...

  4. 在Oracle 12C中使用scott账号

    在Oracle11g中默认是有scott账号的,但在Oracle 12C中则不能直接使用. 我的机器环境: 操作系统:Windows Server 2008 R2 64位 Oracle版本:Oracl ...

  5. 为什么一些公司把dwg文件转化为pdf

    是因为dwg文件中可能会涉及到字体问题 这台电脑打开dwg没问题,另一台电脑可能没有相应的字体用autocad打开就会出现乱码,所以先转化为pdf,而pdf有固定格式的作用,能够保证一台电脑打开是什么 ...

  6. oracle date 和 timestamp区别

    在今天的工作中,学到了以下几个知识点: 一.date和timestamp 的区别 date类型是Oracle常用的日期型变量,他的时间间隔是秒.两个日期型相减得到是两个时间的间隔,注意单位是“天”.例 ...

  7. C++笔记--模板

    一个string模板 简单的定义 template <class C>//模板形式,C是一个类型名字,不一定是某个类的名字 class String{ struct srep; srep ...

  8. C++面试笔记--STL模板与容器

    1.C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作.vec ...

  9. 《Maven实战》笔记-8-构建部署Web项目

      一.Web项目结构 1.显式指定Web项目打包方式为war:   2.默认目录 根据“约定大于配置”的规则,Web项目的类及资源文件默认位置为src/main/java和src/main/reso ...

  10. 2 plan team 服务器搭建

    最近想搞个2-plan team看看,是不是适合小型团队任务管理 下了个包,解压了,发现里面的readme太简单了 readme中的install相关的内容如下 ### Installation in ...