【问题标题】:ServiceStack: Serving Static files from a directory when present?ServiceStack:在存在时从目录提供静态文件?
【发布时间】:2013-04-01 13:08:55
【问题描述】:

我正在将我的独立家庭网络服务器转换为使用 ServiceStack 来服务所有页面和资源。

我从这个问题看到

Serving a static file with servicestack

使用服务堆栈很容易为单个静态文件提供服务。

在我的本地实现中,在检查 URL 是否与任何特定处理程序(相当于 ServiceStack 路由)匹配后,默认处理程序会检查其 HttpData 目录中的静态文件以匹配 URL。

如果该文件不存在,则会生成 404 错误。

如果没有其他服务匹配,使用 ServiceStack 从文件系统提供文件的最佳模式是什么?请注意,我在没有 IIS 的情况下以独立模式使用它。

这些文件可以是 HTML、PNG、JS 和少数其他内容类型。

注意:我看到 ServiceStack.Razor 包可以帮助我的要求,但我找不到它的文档。我将提出一个单独的问题。

编辑:我在这个问题中找到了参考

Create route for root path, '/', with ServiceStack

表示

注册一个IAppHost.CatchAllHandlers - 这会为不匹配的请求调用。

到目前为止,我还没有找到任何关于如何 进行此注册的文档或示例。注意:我是单机运行,所以需要在 C# 中完成,而不是 XML。

【问题讨论】:

    标签: c# servicestack


    【解决方案1】:

    经过大量研究,我发现以下似乎有效。

    配置

    在AppHost 构造函数中:

                    CatchAllHandlers.Add(
                        (httpMethod, pathInfo, filePath) => 
                            Tims.Support.StaticFileHandler.Factory(
                                Params.Instance.HttpDataDir, 
                                "/", 
                                pathInfo
                        )
                    );
    

    工厂

    检查文件是否存在,并返回适当的处理程序,如果不处理文件(因为它不存在),则返回 null。这一点很重要,这样其他网址(例如/metadata)才能继续工作。

    处理程序

    实际处理程序的核心方法非常简单。通过覆盖ProcessRequest 并使用适当的资源类型返回文件的字节,工作就完成了。为简单起见,此版本不包括任何用于缓存目的的日期处理。

    示例代码

    public class StaticFileHandler : EndpointHandlerBase
    {
        protected static readonly Dictionary<string, string> ExtensionContentType;
    
        protected FileInfo fi;
    
        static StaticFileHandler()
        {
            ExtensionContentType = new Dictionary<string, string>       (StringComparer.InvariantCultureIgnoreCase) 
            {
                { ".text", "text/plain" },
                { ".js", "text/javascript" },
                { ".css", "text/css" },
                { ".html", "text/html" },
                { ".htm", "text/html" },
                { ".png", "image/png" },
                { ".ico", "image/x-icon" },
                { ".gif", "image/gif" },
                { ".bmp", "image/bmp" },
                { ".jpg", "image/jpeg" }
            };
        }
    
        public string BaseDirectory { protected set; get; }
        public string Prefix { protected set; get; }
    
        public StaticFileHandler(string baseDirectory, string prefix) 
        {            
            BaseDirectory = baseDirectory;
            Prefix = prefix;
        }
    
        private StaticFileHandler(FileInfo fi)
        {
            this.fi = fi;
        }
    
        public static StaticFileHandler Factory(string baseDirectory, string prefix, string pathInfo)
        {
            if (!pathInfo.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
            {
                return null;
            }
    
            var fn = baseDirectory + "/" + pathInfo.After(prefix.Length);
    
            var fi = new System.IO.FileInfo(fn);
    
            if (!fi.Exists)
            {
                return null;
            }
    
           return new StaticFileHandler(fi);
        }   
    
        public override void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
        {
            using (var source = new System.IO.FileStream(fi.FullName, System.IO.FileMode.Open))
            {
                var bytes = source.ReadAllBytes();
                httpRes.OutputStream.Write(bytes, 0, bytes.Length);
            }
    
            // timeStamp = fi.LastWriteTime;                        
    
            httpRes.AddHeader("Date", DateTime.Now.ToString("R"));
            httpRes.AddHeader("Content-Type", ExtensionContentType.Safeget(fi.Extension) ?? "text/plain");                       
        }
    
        public override object CreateRequest(IHttpRequest request, string operationName)
        {
            return null;
        }
    
        public override object GetResponse(IHttpRequest httpReq, IHttpResponse httpRes, object request)
        {
            return null;
        }
    }
    

    【讨论】:

    • 考虑这个问题中的问题:stackoverflow.com/q/14718808/149060 在这种情况下,我们希望返回 index.html,除非 静态文件或其他路由(例如 /metadata ) 存在。您认为可以修改此代码以支持该要求吗?我不确定如何检查是否存在有效路由(当然,提供了文件存在)。
    • 您可以很容易地,是的,通过将空文件名转换为 index.html。在我的用例中,这不是必需的。
    • 我想我对您提到需要从工厂返回 null 以保留对其他路由的访问感到困惑。一般而言,这是对自定义 EndPointHandler 的要求吗?仅用作 CatchAllHandler 时可能会违反这一要求?
    • 我对SS框架不够专业,无法给你一个明确的答案;我怀疑它说链中的给定处理程序选择不处理特定请求,但我是通过查看示例而不是从正式文档中得到的。
    • 我刚刚重读了你上面的问题;处理程序不知道其他服务或处理程序。但是您可以将 /index 的处理程序放在包罗万象的处理程序之前。不确定如何检测 /metadata 等其他处理程序,但这是一个非常奇怪的要求。
    猜你喜欢
    • 2012-08-20
    • 1970-01-01
    • 2017-08-31
    • 2014-02-11
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多