HttpListener如何提供图像

时间:2014-10-22 17:43:39

标签: c# httplistener httplistenerrequest

我正在制作一个简单的网络服务器来提供html,css,js和amp;图像(在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页面需要在屏幕上显示图像,到目前为止它显示的是图像。我知道images目录是正确的,我测试了它。

这是我获取网络服务器代码的地方:here

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

2 个答案:

答案 0 :(得分:3)

我明白了。我创建了一个类来保存数据,内容类型和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;
                }
            }

我还在稍微清理一下代码,但它现在可以提供图像了!

哦......这是我使用的对象:

public class WebServerRequestData
{
    public string RawUrl { get; set; }
    public string ContentType { get; set; }
    public byte[] Content { get; set; }
    public string RawData { get; set; }
}

答案 1 :(得分:1)

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

  1. 空捕捉。你永远不会发现很多错误。
  2. 将二进制数据填充到字符串中。为什么?没有能够往返二进制数据的编码。
  3. 你没有处置ctx。我不明白为什么你需要一个手册终于阻止。使用using
  4. 不受信任的来电者可以将任意路径注入path。我可以通过导航到/img/..\..\web.config(类似的东西)来请求你的web.config文件。
  5. 考虑将一些常见表达式分解为变量。您的ToLower出现了复制和粘贴错误。不要做脏东西,你会有更少的错误。