C# HttpListener如何为图像提供服务

C# HttpListener如何为图像提供服务,c#,httplistener,httplistenerrequest,C#,Httplistener,Httplistenerrequest,我正在制作一个简单的Web服务器来提供html、css、js和图像(用c#完成)。我正在使用HttpListener,我可以让html、javascript和css文件正常工作。我只是在图像方面有点问题。这是我目前正在使用的: if (request.RawUrl.ToLower().Contains(".png") || request.RawUrl.Contains(".ico") || request.RawUrl.ToLower().Contains(".jpg") ||

我正在制作一个简单的Web服务器来提供html、css、js和图像(用c#完成)。我正在使用HttpListener,我可以让html、javascript和css文件正常工作。我只是在图像方面有点问题。这是我目前正在使用的:

        if (request.RawUrl.ToLower().Contains(".png") || request.RawUrl.Contains(".ico") || request.RawUrl.ToLower().Contains(".jpg") || request.RawUrl.ToLower().Contains(".jpeg"))
        {
                string dir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                string[] img = request.RawUrl.Split('/');
                string path = dir + @"\public\imgs\" + img[img.Length - 1];

                FileInfo fileInfo = new FileInfo(path);
                long numBytes = fileInfo.Length;

                FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
                BinaryReader binaryReader = new BinaryReader(fileStream);
                byte[] output = binaryReader.ReadBytes((int)numBytes);
                binaryReader.Close();
                fileStream.Close();

                var temp = System.Text.Encoding.UTF8.GetString(output);
                return temp;
            }
我正在将图像转换为字符串以返回它们(这是我老板建议的方式)。这就是我处理这些请求的方法

private static string SendResponse(HttpListenerRequest request)
这是我的WebServer类Run()方法。对SetContentType的调用只是通过request.RawUrl确定内容类型

public void Run()
    {
        ThreadPool.QueueUserWorkItem((o) =>
        {
            Console.WriteLine("StackLight Web Server is running...");

            try
            {
                while (_listener.IsListening)
                {
                    ThreadPool.QueueUserWorkItem((c) =>
                    {
                        var ctx = c as HttpListenerContext;

                        try
                        {
                            // store html content in a byte array
                            string responderString = _responderMethod(ctx.Request);

                            // set the content type
                            ctx.Response.Headers[HttpResponseHeader.ContentType] = SetContentType(ctx.Request.RawUrl);

                            byte[] buffer = buffer = Encoding.UTF8.GetBytes(responderString);


                            // this writes the html out from the byte array
                            ctx.Response.ContentLength64 = buffer.Length;
                            using(Stream stream = ctx.Response.OutputStream)
                            {
                                stream.Write(buffer, 0, buffer.Length);
                            }
                        }
                        catch (Exception ex)
                        {
                            ConfigLogger.Instance.LogCritical(LogCategory, ex);
                        }
                    }, _listener.GetContext());
                }
            }
            catch (Exception ex)
            {
                ConfigLogger.Instance.LogCritical(LogCategory, ex); 
            }
        });
    }
我的html页面需要在屏幕上显示一个图像,到目前为止,它显示了一个损坏的图像。我知道图像目录是正确的,我已经测试过了

这是我获得Web服务器代码的地方:


我在想,也许我必须更改SendResponse方法以不返回字符串

这里有些非常糟糕的东西:

  • 空渔获量。你永远也找不到很多虫子
  • 将二进制数据填充到字符串中。为什么?没有能够往返二进制数据的编码
  • 您没有处理
    ctx
    。我不明白你为什么需要手动挡块。使用
    使用
  • 不受信任的呼叫者可以将任意路径注入
    路径
    。我可以通过导航到
    /img/.\..\web.config
    (类似的内容)来请求您的web.config文件

  • 考虑将一些常用表达式分解为变量。您的
    ToLower
    出现复制粘贴错误。不要做肮脏的事,你会有更少的臭虫。

    我想出来了。我创建了一个类来保存数据、内容类型和request.RawUrl。然后,在传递字符串的地方,我将其更改为传递我创建的对象

    因此,对于我的WebServer类,我的Run方法如下所示:

    public void Run()
        {
            ThreadPool.QueueUserWorkItem((o) =>
            {
                Console.WriteLine("StackLight Web Server is running...");
    
                try
                {
                    while (_listener.IsListening)
                    {
                        ThreadPool.QueueUserWorkItem((c) =>
                        {
                            var ctx = c as HttpListenerContext;
    
                            try
                            {
                                // set the content type
                                ctx.Response.Headers[HttpResponseHeader.ContentType] = SetContentType(ctx.Request.RawUrl);
                                WebServerRequestData data = new WebServerRequestData();
    
                                // store html content in a byte array
                                data = _responderMethod(ctx.Request);
    
                                string res = "";
                                if(data.ContentType.Contains("text"))
                                {
                                    char[] chars = new char[data.Content.Length/sizeof(char)];
                                    System.Buffer.BlockCopy(data.Content, 0, chars, 0, data.Content.Length);
                                    res = new string(chars);
                                    data.Content = Encoding.UTF8.GetBytes(res);
                                }
    
                                // this writes the html out from the byte array
                                ctx.Response.ContentLength64 = data.Content.Length;
                                ctx.Response.OutputStream.Write(data.Content, 0, data.Content.Length);
                            }
                            catch (Exception ex)
                            {
                                ConfigLogger.Instance.LogCritical(LogCategory, ex);
                            }
                            finally
                            {
                                ctx.Response.OutputStream.Close();
                            }
                        }, _listener.GetContext());
                    }
                }
                catch (Exception ex)
                {
                    ConfigLogger.Instance.LogCritical(LogCategory, ex); 
                }
            });
        }
    
    我的SendResponse方法如下所示:

    private static WebServerRequestData SendResponse(HttpListenerRequest request)
        {
            string dir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            string[] fileUrl = request.RawUrl.Split('/');
    
            // routes
            if (request.RawUrl.Contains("/"))
            {
                // this is the main page ('/'), all other routes can be accessed from here (including css, js, & images)
                if (request.RawUrl.ToLower().Contains(".png") || request.RawUrl.ToLower().Contains(".ico") || request.RawUrl.ToLower().Contains(".jpg") || request.RawUrl.ToLower().Contains(".jpeg"))
                {
                    try
                    {
                        string path = dir + Properties.Settings.Default.ImagesPath + fileUrl[fileUrl.Length - 1];
    
                        FileInfo fileInfo = new FileInfo(path);
                        path = dir + @"\public\imgs\" + fileInfo.Name;
    
                        byte[] output = File.ReadAllBytes(path);
    
                        _data = new WebServerRequestData() {Content = output, ContentType = "image/png", RawUrl = request.RawUrl};
                        //var temp = System.Text.Encoding.UTF8.GetString(output);
    
                        //return Convert.ToBase64String(output);
                        return _data;
                    }
                    catch(Exception ex)
                    {
                        ConfigLogger.Instance.LogError(LogCategory, "File could not be read.");
                        ConfigLogger.Instance.LogCritical(LogCategory, ex);
                        _errorString = string.Format("<html><head><title>Test</title></head><body>There was an error processing your request:<br />{0}</body></html>", ex.Message);
                        _byteData = new byte[_errorString.Length * sizeof(char)];
                        System.Buffer.BlockCopy(_errorString.ToCharArray(), 0, _byteData, 0, _byteData.Length);
    
                        _data = new WebServerRequestData() { Content = _byteData, ContentType = "text/html", RawUrl = request.RawUrl };
                        return _data;
                    }
                }
    

    不能将图像文件任意解码为UTF8字符串,因为该文件的字节不表示UTF8字符串。您可以(1)使用
    Convert.ToBase64()
    Convert.FromBase64String()
    ,或者更好的选择(2)根本不使用字符串-返回
    文件流
    ,然后使用
    CopyTo()
    将其直接发送到响应的输出流。我认为问题是因为我返回了一个字符串。因此,我应该将函数的返回类型更改为FileStream?我可以使用convert.ToBase64()使favicon.ico正常工作,但我需要显示的png仍然无法正常工作。我使用“using”修复了空捕获和ctx的处理。我该如何让我的图像显示在我的页面上呢?我不知道该怎么做。我还编辑了我的问题以反映这些变化。我如何防止注入(我想这是一个单独的问题)我需要什么来存储二进制数据?有人建议使用Convert.ToBase64String(),但这仍然是一个字符串。将二进制数据存储在字符串中会产生什么后果?这只是意味着我无法将其转换为图像,对吗?我应该只传递字节数组吗?我在想,我可能应该将SendResponse方法的返回类型从string更改为我将创建的存储内容类型和返回数据的对象。如果要传递和发送字节,请使用包含字节的数据结构。例如,字节[]或流(可能是文件流或内存流)。考虑使用文件。是的,使用封装内容和内容类型的对象是一个好主意。这是很好的面向对象和功能设计。
    public class WebServerRequestData
    {
        public string RawUrl { get; set; }
        public string ContentType { get; set; }
        public byte[] Content { get; set; }
        public string RawData { get; set; }
    }