• revel扩展mime类型


          最近在学习ffos的应用开发,需要为每一个应用写一个manifest.webapp文件。这个文件是json格式的,但是不能以application/json类型返回,返回的Content-Type必须是application/x-web-app-manifest+json。

          刚开始用了一个笨方法来实现的。通过查看Static模块的代码,看到public下的文件,是通过RenderFile来实现的。就增加了一个filter,如果请求的文件是以.webapp为后缀名的,就通过c.Response.WriteHeader()来设置返回的Content-Type。这样,ffos的模拟器就可以通过这个manifest.webapp来安装这个web应用了。但是这样做有个小问题,当WriteHeader的时候,会出现一个error log:server.go:597: http: multiple response.WriteHeader calls。具体原因待查明。

          后来仔细看ffos的文档(链接在此:https://developer.mozilla.org/en-US/docs/Web/Apps/Manifest),发现里面写明了在apache和nginx下的Content-Type配置,在配置文件里增加了对应的MIME类型,web server就可以自动返回对应的Content-Type。以前在读revel源码的时候,好像见到了关于mime的东西。于是一顿“find xxx | grep xxx”。终于找到了revel中mime的配置,代码在github.com/robfig/revel/conf/mime-types.conf。只要增加一行:webapp=application/x-web-app-manifest+json,就可以了。迅速删掉之前非常2b的实现。

          后续:

          mime配置的地方找到了,那么它是在哪里读取并返回的呢?

          1.加载:github.com/robfig/revel/revel/run.go中runApp函数里,调用revel.LoadMimeConfig()。也就是说程序一跑起来,就加载一次。

          2.LoadMimeConfig的实现是在github.com/robfig/revel/util.go中,关键一句:

    mimeConfig, err = LoadConfig("mime-types.conf")

             看到就是我前面修改的那个文件,mime-types.conf。

          3.当请求一个static文件时,通过返回一个BinaryResult,来进行response的数据填写。看文件results.go中的一段代码:

    func (r *BinaryResult) Apply(req *Request, resp *Response) {
        disposition := string(r.Delivery)
        if r.Name != "" {
            disposition += fmt.Sprintf("; filename=%s", r.Name)
        }
        resp.Out.Header().Set("Content-Disposition", disposition)
    
        // If we have a ReadSeeker, delegate to http.ServeContent
        if rs, ok := r.Reader.(io.ReadSeeker); ok {
            http.ServeContent(resp.Out, req.Request, r.Name, r.ModTime, rs)
        } else {
            // Else, do a simple io.Copy.
            if r.Length != -1 {
                resp.Out.Header().Set("Content-Length", strconv.FormatInt(r.Length, 10))
            }
            resp.WriteHeader(http.StatusOK, ContentTypeByFilename(r.Name))
            io.Copy(resp.Out, r.Reader)
        }
    
        // Close the Reader if we can
        if v, ok := r.Reader.(io.Closer); ok {
            v.Close()
        }
    }

            可以看加黑的一句,通过ContentTypeByFilename函数,从文件名称的名称找到对应的content type。

          4.最后看一下ContentTypeByFilename的实现,还是在util.go中:

    func ContentTypeByFilename(filename string) string {
        dot := strings.LastIndex(filename, ".")
        if dot == -1 || dot+1 >= len(filename) {
            return DefaultFileContentType
        }
    
        extension := filename[dot+1:]
        contentType := mimeConfig.StringDefault(extension, "")
        if contentType == "" {
            return DefaultFileContentType
        }
    
        if strings.HasPrefix(contentType, "text/") {
            return contentType + "; charset=utf-8"
        }
    
        return contentType
    }

            很简单,就是截取后缀名,然后通过之前加载的mimeConfig,找到对应的Content-Type。

  • 相关阅读:
    触发器实现从TagBlinkLogs往历史表TagLocationHis20125插入一条数据,实现的是在不同的条件下改变相应的状态
    v$sql,V$SQLTExT和v$sqlarea区别与联系
    centos 下增加swap空间大小
    【转载】telnet: connect to address 127.0.0.1: Connection refused
    【原】centos系统命令部分不可用
    [转]linux下的ssh配置
    [原]linux 配置 ssh 等效性
    ORA03113: endoffile on communication channel Process ID: 252 Session ID: 1 Serial number: 3
    【转载】使用rlwrap增强Linux中的sqlplus命令行功能
    [转]详细解说:简单CSS3实现炫酷读者墙
  • 原文地址:https://www.cnblogs.com/code-4-fun/p/3499762.html
Copyright © 2020-2023  润新知