Go程序设计语言1.7 一个Web服务器

    xiaoxiao2024-04-21  8

    1.7 一个Web服务器

    使用Go的库非常容易实现一个Web服务器,用来响应像fetch那样的客户端请求。本节将展示一个迷你服务器,返回访问服务器的URL的路径部分。例如,如果请求的URL是http://localhost:8000/hello,响应将是URL.Path = "/hello"。

     

     

    这个程序只有寥寥几行代码,因为库函数做了大部分工作。main函数将一个处理函数和以/开头的URL链接在一起,代表所有的URL使用这个函数处理,然后启动服务器监听进入8000端口处的请求。一个请求由一个http.Request类型的结构体表示,它包含很多关联的域,其中一个是所请求的URL。当一个请求到达时,它被转交给处理函数,并从请求的URL中提取路径部分(/hello),使用fmt.Printf格式化,然后作为响应发送回去。Web服务器将在7.7节进行详细讨论。

    让我们在后台启动服务器。在Mac OS X或者Linux上,在命令行后添加一个&符号;在微软Windows上,不需要&符号,而需要单独开启一个独立的命令行窗口。

     

    可以从命令行发起客户请求:

     

    另外,还可以通过浏览器进行访问,如图1-2所示。

    为服务器添加功能很容易。一个有用的扩展是一个特定的URL,它返回某种排序的状态。例如,这个版本的程序完成和回声服务器一样的事情,但同时返回请求的数量;URL

    /count请求返回到现在为止的个数,去掉/count请求本身:

     

     

     

     

    这个服务器有两个处理函数,通过请求的URL来决定哪一个被调用:请求/count调用counter,其他的调用handler。以/结尾的处理模式匹配所有含有这个前缀的URL。在后台,对于每个传入的请求,服务器在不同的goroutine中运行该处理函数,这样它可以同时处理多个请求。然而,如果两个并发的请求试图同时更新计数值count,它可能会不一致地增加,程序会产生一个严重的竞态bug(参考9.1节)。为避免该问题,必须确保最多只有一个goroutine在同一时间访问变量,这正是mu.Lock()和mu.Unlock()语句的作用。第9章将更细致地讨论共享变量的并发访问。

    作为一个更完整的例子,处理函数可以报告它接收到的消息头和表单数据,这样可以方便服务器审查和调试请求:

     

    这里使用http.Request结构体的成员来产生类似下面的输出:

     

     

    注意这里是如何在if语句中嵌套调用ParseForm的。Go允许一个简单的语句(如一个局部变量声明)跟在if条件的前面,这在错误处理的时候特别有用。也可以这样写:

     

    但是合并的语句更短而且可以缩小err变量的作用域,这是一个好的实践。2.7节将介绍作用域。

    这些程序中,我们看到了作为输出流的三种非常不同的类型。fetch程序复制HTTP响应到文件os.Stdout,像lissajous一样;fetchall程序通过将响应复制到ioutil.Discard中进行丢弃(在统计其长度时);Web服务器使用fmt.Fprintf通过写入http.ResponseWriter来让浏览器显示。

    尽管三种类型细节不同,但都满足一个通用的接口(interface),该接口允许它们按需使用任何一种输出流。该接口(称为io.Writer)将在7.1节进行讨论。

    Go的接口机制是第7章的内容,但是为了说明它可以做什么,我们来看一下整合Web服务器和lissajous函数是一件多么容易的事情,这样GIF动画将不再输出到标准输出而是HTTP客户端。简单添加这些行到Web服务器:

     

    或者也可以:

     

    上面HandleFunc函数中立即调用的第二个参数是函数字面量,这是一个在该场景中使用它时才定义的匿名函数,这将在5.6节进一步解释。

    一旦你完成这个改变,就可以通过浏览器访问http://localhost:8000。每次加载页面,你将看到一个类似图1-3的动画。

    练习1.12:修改利萨茹服务器以通过URL参数读取参数值。例如,你可以通过调整它,使得像http://localhost:8000/?cycles=20这样的网址将其周期设置为20,以替代默认的5。使用strconv.Atoi函数来将字符串参数转化为整型。可以通过go doc strconv.Atoi来查看文档。

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)