在Golang中实现GitHub徽章

5
我之前在Stack Overflow上提过这个问题,但没有得到令人满意的答案,所以这次我会更具体地描述我的问题。
我想要在golang中实现一个服务器,以svg格式输出动态的状态更新(类似于“Build Passing/Failing”GitHub标徽)。目的是可以将服务器地址嵌入GitHub自述文件中,并且该文件应该根据服务器状态自动更新。
这里是我编写的golang代码,但它似乎不能与GitHub的强缓存一起使用。我需要添加更多的Cache-Control头吗?我需要添加ETag吗?
我正在使用以下内容将图像嵌入GitHub自述文件中。
[![Mine](http://58dcd0b5.ngrok.com/view)]()

理想情况下,我希望每次加载GitHub自述文件时都能更换图片 - 在“正确/错误”两个图像之间切换。(这只是一个概念验证。)
package main

import (
    "log"
    "net/http"
    _ "time"
)
var mymap map[string][]byte

var state bool = false


func viewHandler(w http.ResponseWriter, r *http.Request) {
    log.Printf("State %v", state)
    state = !state
    w.Header().Set("Content-Type", "image/svg+xml")
    w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
    if state {
        w.Write(mymap["correct"])
    } else {
        w.Write(mymap["wrong"])
    }
}

func main() {
    mymap = make(map[string][]byte)
    mymap["correct"] = []byte(`<svg xmlns="http://www.w3.org/2000/svg" width="104" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><mask id="a"><rect width="104" height="20" rx="3" fill="#fff"/></mask><g mask="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h50v20H54z"/><path fill="url(#b)" d="M0 0h104v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="28" y="15" fill="#010101" fill-opacity=".3">solution</text><text x="28" y="14">solution</text><text x="78" y="15" fill="#010101" fill-opacity=".3">correct</text><text x="78" y="14">correct</text></g></svg>`)
    mymap["wrong"] = []byte(`<svg xmlns="http://www.w3.org/2000/svg" width="99" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><mask id="a"><rect width="99" height="20" rx="3" fill="#fff"/></mask><g mask="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#e05d44" d="M54 0h45v20H54z"/><path fill="url(#b)" d="M0 0h99v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="28" y="15" fill="#010101" fill-opacity=".3">solution</text><text x="28" y="14">solution</text><text x="75.5" y="15" fill="#010101" fill-opacity=".3">wrong</text><text x="75.5" y="14">wrong</text></g></svg>`)

    mux := http.NewServeMux()
    mux.HandleFunc("/view", viewHandler)
    http.ListenAndServe(":8085", mux)
}

请查看 http://shields.io 并了解他们如何提供图像。 - Jamesking56
3个回答

4
以下是Travis为其图像提供的内容:

以下是Travis为其图像提供的内容:

Age:0
Cache-Control:no-cache
Content-Length:0
Date:Mon, 30 Mar 2015 07:49:10 GMT
ETag:"88e168c2d5cdb30ee9af739765e78e4d"
Expires:Mon, 30 Mar 2015 07:49:10 GMT
Keep-Alive:timeout=10, max=48
Last-Modified:Wed, 07 Jan 2015 11:26:53 GMT
Timing-Allow-Origin:https://github.com
X-Timer:S1427701750.146025,VS0,VE156

尝试这些方法并看看哪种方法有效可能是一个不错的开始。


3
当然不要盲目地从其他来源复制“ETag”等标题。理想情况下,应该了解缓存以及如何通过标题来控制缓存,这样就不会做出傻瓜式的行为或者像禁止某些只在一定时间内偶尔更改或只能更改一次的内容的所有缓存一样浪费资源。 - Dave C

4
这里有一个关于此问题的Github问题:https://github.com/github/markup/issues/224 资产必须包括Cache-Control: no-cache和ETag标头。如果徽章没有更新,则意味着它们没有正确设置这些标头。
资产还可能需要包括ETag或Expires标头。Fastly的缓存控制文档表示,no-cache表示“在提供此内容之前重新验证”,但它没有指定如何“重新验证”。我猜它正在重新验证,但没有表明资产是否已更改,因此它继续提供缓存的资产。
ETag将是最大的胜利,因为它将保证在更改时刷新缓存,但仍节省带宽。

1

跟随此次提交到shields.io服务器,我对上述代码进行了以下更改,现在它可以正常工作。

w.Header().Set("Date", date)
w.Header().Set("Expires", date)

为了完整性(以及如果有人想要尝试它),这里是完整的代码。 (也可以在GitHub上找到。)

package main

import (
    "log"
    "net/http"
    "time"
)

var mymap map[string][]byte

var state bool = false

func viewHandler(w http.ResponseWriter, r *http.Request) {
    date := time.Now().Format(http.TimeFormat)
    log.Printf("%v", date)
    log.Printf("State %v", state)
    state = !state
    w.Header().Set("Content-Type", "image/svg+xml")
    w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
    w.Header().Set("Date", date)
    w.Header().Set("Expires", date)
    if state {
        w.Write(mymap["correct"])
    } else {
        w.Write(mymap["wrong"])
    }
}

func main() {
    mymap = make(map[string][]byte)
    mymap["correct"] = []byte(`<svg xmlns="http://www.w3.org/2000/svg" width="104" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><mask id="a"><rect width="104" height="20" rx="3" fill="#fff"/></mask><g mask="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h50v20H54z"/><path fill="url(#b)" d="M0 0h104v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="28" y="15" fill="#010101" fill-opacity=".3">solution</text><text x="28" y="14">solution</text><text x="78" y="15" fill="#010101" fill-opacity=".3">correct</text><text x="78" y="14">correct</text></g></svg>`)
    mymap["wrong"] = []byte(`<svg xmlns="http://www.w3.org/2000/svg" width="99" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><mask id="a"><rect width="99" height="20" rx="3" fill="#fff"/></mask><g mask="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#e05d44" d="M54 0h45v20H54z"/><path fill="url(#b)" d="M0 0h99v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="28" y="15" fill="#010101" fill-opacity=".3">solution</text><text x="28" y="14">solution</text><text x="75.5" y="15" fill="#010101" fill-opacity=".3">wrong</text><text x="75.5" y="14">wrong</text></g></svg>`)

    mux := http.NewServeMux()
    mux.HandleFunc("/view", viewHandler)
    log.Println("Server started. Listening on 8085...")
    http.ListenAndServe(":8085", mux)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接