You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在HttpSelfHostServer中实现Web API的图片访问功能?

在HttpSelfHostServer中实现静态图片访问

HttpSelfHostServer没有OWIN生态中的UseFileServer这类静态资源处理扩展,需要手动实现静态图片的访问逻辑,下面提供两种可行方案:

方案一:通过ApiController处理静态图片请求

步骤1:创建静态文件控制器

新增一个ImagesController,负责读取本地图片并返回响应:

using System.IO;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace WebAPIServerV2.Controllers
{
    public class ImagesController : ApiController
    {
        // 本地图片存储根路径,可根据实际场景调整
        private readonly string _imageRoot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");

        [HttpGet]
        public HttpResponseMessage Get(string filename)
        {
            var filePath = Path.Combine(_imageRoot, filename);
            
            if (!File.Exists(filePath))
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            var response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StreamContent(fileStream)
            };

            // 根据文件扩展名设置正确的Content-Type
            var ext = Path.GetExtension(filename).ToLowerInvariant();
            switch (ext)
            {
                case ".jpg":
                case ".jpeg":
                    response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
                    break;
                case ".png":
                    response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
                    break;
                case ".gif":
                    response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/gif");
                    break;
                default:
                    response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
                    break;
            }

            return response;
        }
    }
}

步骤2:添加静态资源路由

在Start方法中,新增匹配images/{filename}的路由(需放在原有API路由之前,避免被拦截):

public void Start(string url)
{
    if (m_Server != null)
    {
        Stop();
    }

    var config = new HttpSelfHostConfiguration(url);
    config.DependencyResolver = new AutofacWebApiDependencyResolver(m_lifetimeScope);
    config.MaxReceivedMessageSize = int.MaxValue;

    // 静态图片路由
    config.Routes.MapHttpRoute(
        name: "StaticImages",
        routeTemplate: "images/{filename}",
        defaults: new { controller = "Images", action = "Get" }
    );

    // 原有API路由
    config.Routes.MapHttpRoute(
        name: "ServerAPI",
        routeTemplate: "server/{controller}/{action}"
    );

    // 原有格式化配置
    config.Formatters.Clear();
    config.Formatters.Add(new JsonMediaTypeFormatter());
    config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new StringEnumConverter());
    config.Formatters.JsonFormatter.SerializerSettings =
    new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver()
    };

    m_Server = new HttpSelfHostServer(config);
    m_Server.OpenAsync().Wait();
    if (Environment.UserInteractive)
        Console.WriteLine($"WebAPI server start at:{url}");
}

注意事项

  • 确保项目根目录下存在Images文件夹,或修改_imageRoot指向实际存储路径
  • 保证应用程序对目标文件夹有读取权限
  • 可扩展逻辑添加缓存头、文件大小限制等优化

方案二:自定义HttpMessageHandler处理静态资源

若不想通过控制器,可直接在消息处理层拦截静态资源请求:

步骤1:创建静态文件处理器

using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace WebAPIServerV2
{
    public class StaticFileHandler : DelegatingHandler
    {
        private readonly string _staticRoot;
        private readonly string _routePrefix = "/images/";

        public StaticFileHandler(string staticRoot)
        {
            _staticRoot = staticRoot;
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var requestPath = request.RequestUri.AbsolutePath;
            if (requestPath.StartsWith(_routePrefix, System.StringComparison.OrdinalIgnoreCase))
            {
                var filename = requestPath.Substring(_routePrefix.Length);
                var filePath = Path.Combine(_staticRoot, filename);

                if (File.Exists(filePath))
                {
                    var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                    var response = new HttpResponseMessage(HttpStatusCode.OK)
                    {
                        Content = new StreamContent(fileStream)
                    };

                    // 设置Content-Type
                    var ext = Path.GetExtension(filename).ToLowerInvariant();
                    switch (ext)
                    {
                        case ".jpg":
                        case ".jpeg":
                            response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
                            break;
                        case ".png":
                            response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
                            break;
                        case ".gif":
                            response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/gif");
                            break;
                        default:
                            response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
                            break;
                    }

                    return response;
                }
                else
                {
                    return new HttpResponseMessage(HttpStatusCode.NotFound);
                }
            }

            // 非静态资源请求,交给后续处理器处理
            return await base.SendAsync(request, cancellationToken);
        }
    }
}

步骤2:注册处理器到配置

在Start方法中添加自定义处理器:

public void Start(string url)
{
    if (m_Server != null)
    {
        Stop();
    }

    var config = new HttpSelfHostConfiguration(url);
    config.DependencyResolver = new AutofacWebApiDependencyResolver(m_lifetimeScope);
    config.MaxReceivedMessageSize = int.MaxValue;

    // 注册静态文件处理器
    var imageRoot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
    config.MessageHandlers.Add(new StaticFileHandler(imageRoot));

    // 原有路由配置
    config.Routes.MapHttpRoute(
        name: "ServerAPI",
        routeTemplate: "server/{controller}/{action}"
    );

    // 原有格式化配置
    config.Formatters.Clear();
    config.Formatters.Add(new JsonMediaTypeFormatter());
    config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new StringEnumConverter());
    config.Formatters.JsonFormatter.SerializerSettings =
    new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver()
    };

    m_Server = new HttpSelfHostServer(config);
    m_Server.OpenAsync().Wait();
    if (Environment.UserInteractive)
        Console.WriteLine($"WebAPI server start at:{url}");
}

注意事项

  • 此方式无需额外控制器,直接在消息拦截层处理,性能略优
  • 同样需确保静态文件目录存在且有读取权限

内容的提问来源于stack exchange,提问作者Izikon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 08:45:30