第七章 GO语言实现网站

一 :我们先用一个小例子来看一下Go的web开发
package main
 
import (
"net/http"
"io"
"log"
)
 
func helloHandler(w http.ResponseWriter,r *http.Request) {
io.WriteString(w,"赵占龙 ——汽车之家")
}
func zzltty(w http.ResponseWriter,r *http.Request) {
io.WriteString(w,"这个是另外一个页面——测试GO路由")
}
func main() {
http.HandleFunc("/hello",helloHandler)
http.HandleFunc("/zzl",zzltty)
err :=http.ListenAndServe(":8080",nil)
if err !=nil{
log.Fatal("出错了:",err.Error())
}
}
 
这样当我们在浏览器请求  http://localhost:8080/hello的时候就会看到
 
我们引入net/http包,主要用于提供web服务,响应并处理客户端的http请求,同事使用io包而不是fmt包来输出字符串,这样源文件编译成可执行文件后,体积要 很多,运行起来更节省资源
 
通过上面的程序我们可以看出 ,我们在main函数中使用
http.HandleFunc来做url路由映射,这个方法接收两个参数,第一个是http请求的目标路径,该参数可以是string字符串也可以是正则表达式,第二个是指定具体的回答方法,就是action
 
并且我们使用http.ListenAndServe来监控端口8080,看到了吧Go语言开启Http搭建一个web就这么简单,不需要在用 iis配置什么的啦 
 
二;项目开发一个简单的相册网站
 
图片上传:
 
 
package main
 
import (
"net/http"
"io"
"log"
"os"
"io/ioutil"
"html/template"
)
 
const (
pathstr="D:/Go_work/webtest/zzl/"
 
temppath="D:/Go_work/webtest/temphtml/"
)
 
func uploadHandler(w http.ResponseWriter,r *http.Request) {
if r.Method=="GET"{
//w.Header().Set("Content-Type","text/html")
//io.WriteString(w,"<form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\" />"+
// "kai shi shang chuan:"+
// "<input name=\"image\" type=\"file\" />"+"<input type=\"submit\" value=\"upload\" /></form>")
 
//template.ParseFiles函数指定模板内容,并返回一个 *template.ParseFiles值
t,err :=template.ParseFiles("upload.html")
if err !=nil{
http.Error(w,err.Error(),http.StatusInternalServerError)
return
}
//t.Execute 方法会根据模板语法来执行模板渲染,并将渲染后的结果作为HTTp的返回数据输出
t.Execute(w,nil)
return
}
if r.Method=="POST"{
//r.FormFile 获取表单中的数据
f,h,err :=r.FormFile("image")
if err !=nil{
//输出一个http错误信心 http.StatusInternalServerError这个是http错误码
http.Error(w,err.Error()+"111",http.StatusInternalServerError)
return
}
//获取上传的文件名
filename :=h.Filename
//关闭上传流
defer f.Close()
//os.Create 在指定的位置创建一个文件
t,err :=os.Create(pathstr+filename)
if err!=nil{
http.Error(w,err.Error()+"222",http.StatusInternalServerError)
return
}
defer t.Close()
//io.Copy(t,f) 把上传的文件写入到刚才 os.create创建的文件中
if _,err :=io.Copy(t,f);err !=nil{
http.Error(w,err.Error()+"333",http.StatusInternalServerError)
return
}
http.Redirect(w,r,"/view?id="+filename,http.StatusFound)
}
 
}
 
func viewHandler(w http.ResponseWriter,r *http.Request) {
//r.FormValue获取浏览器url后面的参数的值
imgaeid :=r.FormValue("id")
imagepath :=pathstr+imgaeid
if exists :=isExists(imagepath); !exists{
http.NotFound(w,r)
return
}
//设置输出头类型
w.Header().Set("Content-Type","image")
//http.ServeFile吧本地文件写入到http输出流中
http.ServeFile(w,r,imagepath)
}
func isExists(path string) bool {
//os.stat判断文件是否存在
_,err :=os.Stat(path)
if err ==nil{
return true
}
return os.IsExist(err)
}
 
func listHandler(w http.ResponseWriter,r *http.Request) {
//设置输出头
w.Header().Add("Content-Type","text/html")
//查询目录下所有文件返回的事一个array
fileinfoArr,err :=ioutil.ReadDir(pathstr)
if err !=nil{
http.Error(w,err.Error(),http.StatusInternalServerError)
return
}
//var listHtml string
//for _,fileinfo :=range fileinfoArr{
// imageid :=fileinfo.Name()
// listHtml +="<li><a href=\"/view?id="+imageid+"\">"+imageid+"</a></li>"
//}
//io.WriteString(w,listHtml)
 
 
locals :=make(map[string]interface{})
images :=[]string{}
for _,fileinfo :=range fileinfoArr{
images=append(images,fileinfo.Name())
}
locals["images"] =images
t,err :=template.ParseFiles("list.html")
if err !=nil{
http.Error(w,err.Error(),http.StatusInternalServerError)
return
}
//方法会根据模板语法来执行模板渲染,并将渲染后的结果作为HTTp的返回数据输出(并且吧数据传输模板)
t.Execute(w,locals)
}
 
 
func staticDirHandler(mux *http.ServeMux,prefix string,staticDir string ,flags int) {
mux.HandleFunc(prefix, func(w http.ResponseWriter, r *http.Request) {
file :=staticDir+r.URL.Path[len(prefix)-1:]
if exists :=isExists(file); !exists{
http.NotFound(w,r)
return
}
http.ServeFile(w,r,file)
})
}
 
 
func main() {
 
//动静分离
mux :=http.NewServeMux()
//这样所有网站求情里面带/zz/的url都会被当做静态资源处理,对应到D:/zzl/文件
staticDirHandler(mux,"/zzl/","D:/zzl/",0)
 
 
//设置url路由
http.HandleFunc("/upload",uploadHandler)
http.HandleFunc("/view",viewHandler)
http.HandleFunc("/",listHandler)
err :=http.ListenAndServe(":8080",nil)
if err !=nil{
log.Fatal("ListenAndServe监控失败:",err.Error())
}
}
 
模板缓存:在上面的代码中,不管是list显示还是view显示,没操作一次都会加载一次html模板,显然这样做是很低效的,但是Go语言给我们提供了很好的处理机制,就是一次性预加载模板,Go语言准许我们在init()函数做这样的事情,init函数会在main函数之前执行
 
在上面的代码中补全两个方法做一下模板的预加载
 
var templates :=make(map[string]*template.Template)
 
func init() {
fileListArrs,err :=ioutil.ReadDir(temppath)
if err !=nil{
panic(err)
return
}
var templatename,templatepath string
 
for _,fileinfo :=range fileListArrs{
templatename=fileinfo.Name()
if ext :=path.Ext(templatename);ext !=".html"{
continue
}
templatepath=temppath+templatename
log.Println("模板地址",templatepath)
t :=template.Must(template.ParseFiles(templatepath))
templates[templatename]=t
}
 
}
 
func renderHtml(w http.ResponseWriter,tmpl string,locals map[string]interface{}) {
templates[tmpl].Execute(w,locals)
}
 
 
https的支持
 
package main
 
import (
"net/http"
"fmt"
)
 
const(
Server_Port=8080
Server_Domain="localhost"
ResPon="hello"
)
 
func rootHandler(w http.ResponseWriter,r *http.Request) {
w.Header().Set("Content-Type","text/html")
w.Write([]byte(ResPon))
}
 
func main() {
http.HandleFunc(fmt.Sprintf("%s:%d",Server_Domain,Server_Port),rootHandler)
http.ListenAndServeTLS(fmt.Sprintf(":%d",Server_Port),"rui.crt","rui.key",nil)
}
 
 
 
posted @ 2018-08-03 18:12  瀚海行舟  阅读(568)  评论(0编辑  收藏  举报