第五章的示例 正是我想做的一个东西,所以我会慢慢将该示例丰富。而且该示例由浅入深,层层递进,写得很不错,特别适合学习。
还没有全部完成,就已经遇到了几个问题。希望可以解答。
- 在没有使用html模版之前,html相关的代码如果不添加<html></html>的标签,是不会解析html的。但是同样的代码不包含<html></html>标签,单独写在1.html文件里面用浏览器打开又是可以的,是因为go的html函数解析必需要html标签吗?
- 在listHandler方法里面,_,fileInfo := range fileInfoArr 获取到了文件的相关信息,但是使用imgid := fileInfo.Name 出现了一个问题,该如何使用。 method fileInfo.Name is not an expression, must be called
- 另外几个小问题都是印刷问题在viewHandler里面的imageId和imagePath 都没有定义 改成:=就可以了。
- 还有一个问题,因为这里省略了缩略图(不是本章的重点),而想实现该功能,自己在网上找一了个resize.go https://github.com/nfnt/resize 不知道这个怎么样,实际操作处理缩略图的速度很慢。还没有仔细研究,有没有比较成熟的代码和建议。
继上次提出的几个问题后:
- 在模版缓存这里开始,定义了一个templates,这个是全局的一个变量,定义在函数体之外,是不能使用:=的短格式,可能是copy的原因导致的,需要使用var定义。var templates = map[string]*template.Template{} 和var templates = make(map[string]*template.Template) 这两个的定义都是可以的 我想问的是他们有区别吗?
- 再有个问题是 templatesp[tmpl]=t 这里并没有tmpl这个变量 我想是截取代码时候造成的,但并没有测试代码,tmpl应该是upload 或者list,所以对templateName进行了split操作。
- 使用了check函数后,代码相应的变化,但有些地方忘了添加check有些地方err:= 不再需要:号 因为没有if所以没有了局部变量。
- safeHandler函数里面http.Error( w,err.Error(),http.StatusInternalServerError ) err要么改要么其它地方改 没有统一
- 在动静分离的时候定义了一个常量ListDir=0x001,这个十六进制的数与flags进行位运算没有太明白原理,书中因为简略的描述,没有太明白,能麻烦详细解释下吗?
- 在查看图片的时候 会打印 2012/10/26 17:54:14 http: StatusNotModified response with header "Content-Type" defined 是因为这个设置报出来的吗? w.Header().Set("Content-Type","image") ,另外image写得是否正确?
- 最后,整个示例的层层递进关系非常好,非常感谢。但示例最后好像因为截取copy等关系并没有严格的测试,还有一些格式等小问题,我将代码放置在了我的blog上面,有时间会整理所有章节的问题和示例代码进行打包发布。关于这章的http://www.ohlinux.com/archives/825/
这章的示例还在完善,做个小相册玩玩。
Q1: html 标签渲染和 golang 函数没有关系,用
<html>
标签包裹HTML<body>
是 html 的语法要求。书中的示例代码是简写形式,用代码输出html body,目的是为了便于过渡理解后续模板使用。考虑到读者不可能全是做过web开发碰过html的,这里略微讲下 html 基础。
纯粹用
<html>
标签包裹起来,不同的浏览器理解行为也不一样的。严格意义上的HTML语法,在
<html>
标签之上,也即更外部一层,需要声明 Doctype tag,而 doctype 又分多种类型,比如:XHTML DOCTYPES
doctype html
doctype 5
doctype 1.1
doctype strict
doctype frameset
doctype mobile
doctype basic
doctype transitional
HTML 4 DOCTYPES
doctype strict
doctype frameset
doctype transitional
针对 PC 端的桌面浏览器,现在用的最多的就是 doctype 1.1 标准
doctype 1.1
加上现在 HTML5 这波热潮,doctype 5 用的也比较流行。
doctype 5
其中,doctype 1.1 标准最通用,各浏览器都能良好理解。但 doctype 5 只对支持HTML5特性的浏览器有较好的支持。
再回到正题,书里边的样例代码部分是示范性的,比如下面的 “代码片段1” 作为一个网页雏形,目的是为了便于过渡理解 “代码片段2”中的模板使用,如果楼主顺着章节看下去不难理解这是一种循序渐进的讲解。因为看到章节的末尾会有完整的工程源代码,也有标准的HTML模板文件,最终实现了一个精简的MVC 模型,可以像个正常的网站程序跑起来。
// 代码片段1
// 代码片段2
// 按照楼主要求,加上 html 标签,代码片段1应该如下写,浏览器可以渲染成网页
《Go语言编程》是一本不厚很简洁的书,本身是因为Go简洁高效的表达,书中的内容更多的是展现Go语言如何编程及其实践使用。“用Go语言开发网站” 只是书中[网络编程]这章的一小节内容,以简短的篇幅展现了用原生的Go语言而不是借助任何第三方框架或者库来开发一个网站的具体细节,相信有过web开发基础的朋友不难理解。不过作者没有把普及 HTML 基础知识写在本书内。
Q2 and Q3: 不确定是不是排版印刷问题,我这里的原稿源代码显示如下,请自行更正:
Q2 代码片段
Q3 代码片段
书中的代码错误我们会和出版社联系,新的印刷中避免出现。
Q4: Go语言关于处理图像的原生库目前不太成熟,我们也试验过Go的图像处理最后放弃,生产环境中没有使用。成熟的图像处理工具可以参考 ImageMagick 或者 GraphicsMagick,也可以使用 七牛云存储提供的在线图像处理接口
以下内容作为楼主修改问题后的补充回答。
templates
变量就是全局的。并非局部定义,为确定我心中的疑惑,我刚才看了下我们这边的电子书稿,是使用如下方式声明的。然后,我自己看书翻阅,发现代码确实是使用
:=
形式声明在函数体之外的,囧。我表示找不出合适理由解释,但可以承诺会和出版社沟通书中存在样例代码错误的问题。楼主可以私信给我你的收货地址,更新后的书我买本寄送给你。以下两段代码是等价的。
两者的共同之处在于:返回“该map结构”的初始化值。
不同之处在于:
make()
可用于创建 slices, maps, channels。比如创建 slice 时,完整的语法规格如下:关于
make()
的细节,可以查阅书中相应的基础章节。为了确认书中是否存在印刷错误,我又看了遍书。
tmpl
这个变量我在书中(P150, P151)明明有看到,代码摘抄如下:P150
如上这段代码中的
tmpl
来自 for 循环 range 遍历 string 数组得的的元素。range
是 Go 语言中的保留关键字,可用于循环。range
可以针对 slice、array、string、map 和 channel 类型的数据结构进行迭代操作。基于不同的内容,range 返回不同的东西,基本来讲,会从它循环的内容中返回一个 key/value 。如上代码中,当对 []string 数组(array)做循环时,range 返回序号作为 key(我们用匿名变量下划线_
作丢弃处理),而这个序号所对应的内容(value)作为值赋值给了tmpl
。关于
range
保留关键字的更多细节,可以查阅书中的基础章节。P151
这段代码中的
tmpl
也不是不存在,可以明显看到是从函数renderHtml()
作为参数传入。章节前半部分由于展示关键代码部分可能会少写代码片段,看了下书中章节中的最终代码
photoweb.go
,凡是有err
赋值的地方都紧跟着出现了check(err)
检测。isExists()
函数中未出现check(err)
是因为该函数return os.IsExist(err)
。另需要说明的是:check(err)
表达的是 “把程序错误终止在它该出现的地方” 这样一种思想。实际生产环境中,类似的错误处理可能需要更细致而不是那么笼统。没有看明白这句话的意思,因为没有上下文可以参考所以实在想不出来楼主要表达的意思。
一个
comma,ok
形式的语句,只要是有新变量赋值操作,那么必须用:=
,比如:而当
err
变量已经声明后,在没有新变量赋值操作的情况下,不必用:=
,比如书中样例代码的uploadHandler()
函数,前两个err
赋值语句都用了:=
操作,而第3个err
由于没有产生新变量(_, err = ...
)所有没有用:=
而是直接=
赋值。摘抄代码如下:可能是楼主好心建议,不过没有上下文参考表示没有看明白。尽管没看明白,还是稍作简单理解,应该是章节前半部分的代码片段用到了这样的写法。建议以章节中最终的
photoweb.go
程序为完整示例代码参考。完整示例代码photoweb.go
中,由于重构关系,只有一个地方也即safeHandler()
函数中出现http.Error(w, e.Error(), http.StatusInternalServerError)
。看了下,书中的此处代码显得有些多余;又看了下电子稿,发现跟书上确实有不一致的地方,新版印刷书中会修复此问题。此处的位运算逻辑只是判断要不要列出目录,
flags
为 0 即表示只handle目录中的文件而不列目录。正确的代码如下:w.Header().Set("Content-Type","image")
是作者偷懒简写,但也是可以正常work的,你问题中报的日志跟这个简写没有关系。实际应用中应该输出文件具体的 MIME-Type 类型。比如image/jpg
,image/png
等等。MIME-Type 规格如下:MIME根据type制定了默认的subtype,当客户端不能确定消息的subtype的情况下,消息被看作默认的subtype进行处理。所以,示例程序运行时浏览器可正常显示图片。
非常感谢楼主的热心!:)
不过书中由于篇幅只是写了一个很小很小的web例子,便于读者们理解用原生的Go语言开发web程序所需了解的各个细节。楼主若有兴趣可以写个更实用型的完整web案例!
《Go语言编程》一书的源代码在 Github 上可以找到:https://github.com/qiniu/gobook
photoweb.go 的源代码在此:https://github.com/qiniu/gobook/blob/...
欢迎提交 issues 和 pull requests!
另对书中出现的一些印刷问题,笔者表示非常抱歉,必赠楼主新书一本。