Почему я получаю сообщение об ошибке «(304) Not Modified» в некоторых ссылках при использовании HttpWebRequest? - PullRequest
41 голосов
/ 09 апреля 2010

Любые идеи, почему по некоторым ссылкам, к которым я пытаюсь получить доступ через HttpWebRequest, я получаю «Удаленный сервер возвратил ошибку: (304) Не изменено». в коде?

Код, который я использую, взят из сообщения Джеффа здесь (кажется, что страница исчезла, см. архивную копию на Wayback Machine ).

Обратите внимание, что концепция кода - это простой прокси-сервер, поэтому я указываю своему браузеру на этот локально работающий фрагмент кода, который получает запрос от моего браузера, а затем проксирует его, создавая новый запрос HttpWebRequest, когда вы ' посмотрим в коде. Это прекрасно работает для большинства сайтов / ссылок, но для некоторых эта ошибка появляется. Вы увидите, что один ключевой бит в коде - то, где он, кажется, копирует настройки заголовка http из запроса браузера в его запрос на сайт, и он копирует в атрибуты заголовка. Не уверен, что проблема связана с тем, как он имитирует этот аспект запроса, и что происходит, когда возвращается результат?

case "If-Modified-Since":
   request.IfModifiedSince = DateTime.Parse(listenerContext.Request.Headers[key]);
   break;

Я получаю проблему, например, от http://en.wikipedia.org/wiki/Main_Page

PS. ОБНОВЛЕНИЕ ЗДЕСЬ

Все еще не могу решить это. По сути, я могу определить 1 ссылку, у которой есть проблема, и она, кажется, работает нормально, 2-й раз, когда она получает ошибку, 3-й раз ОК, 4-й раз ошибка, 5-й ОК и т. Д. Как будто есть состояние, которое не очищается или что-то в коде. Я попытался немного очистить код с помощью операторов типа using и т. Д.

Вот код. Если кто-то может определить, почему каждый второй раз, когда я просматриваю ссылку типа http://newsimg.bbc.co.uk/css/screen/1_0_16/nol/v4/story.css (начиная со второго, а не первого) через этот прокси-код, я получаю сообщение об ошибке, которое мне хотелось бы услышать.

class Program
{
    static void Main(string[] args)
    {
        Proxy p = new Proxy(8080);

        Thread proxythread = new Thread(new ThreadStart(p.Start));
        proxythread.Start();

        Console.WriteLine("Proxy Started. Press Any Key To Stop...");
        Console.ReadKey();

        p.Stop();
     }
}

public class Proxy
{
    private HttpListener _listener;
    private int _port;

    public Proxy(int port)
    {
        int defaultport = 8080;

        // Setup Thread Pool
        System.Threading.ThreadPool.SetMaxThreads(50, 1000);
        System.Threading.ThreadPool.SetMinThreads(50, 50);

        // Sanitize Port Number
        if (port < 1024 || port > 65535)
            port = defaultport;

        // Create HttpListener Prefix
        string prefix = string.Format("http://*:{0}/", port);
        _port = port;

        // Create HttpListener
        _listener = new HttpListener();
        _listener.Prefixes.Add(prefix);
    }

    public void Start()
    {
        _listener.Start();

        while (true)
        {
            HttpListenerContext request = null;

            try
            {
                request = _listener.GetContext();

                // Statistics (by Greg)
                int availThreads = -1;
                int compPortThreads = -1;
                ThreadPool.GetAvailableThreads(out availThreads, out compPortThreads);
                log("INFO", request.Request.Url.ToString(), "START - [" + availThreads + "]");

                ThreadPool.QueueUserWorkItem(ProcessRequest, request);
            }
            catch (HttpListenerException ex)
            {
                log("ERROR", "NA", "INFO: HttpListenerException - " + ex.Message);
                break;
            }
            catch (InvalidOperationException ex)
            {
                log("ERROR", "NA", "INFO: InvalidOperationException - " + ex.Message);
                break;
            }
        }
    }

    public void Stop()
    {
        _listener.Stop();
    }

    private void log(string sev, string uri, string message)
    {
        Console.Out.WriteLine(Process.GetCurrentProcess().Id + " - " + sev + " (" + uri + "): " + message);
    }

    private void ProcessRequest(object _listenerContext)
    {
        #region local variables
        HttpWebRequest psRequest;                   // Request to send to remote web server
        HttpWebResponse psResponse;                 // Response from remote web server         
        List<byte> requestBody = new List<byte>();  // Byte array to hold the request's body
        List<byte> responseBody = new List<byte>(); // Byte array to hold the response's body
        byte[] buffer;
        string uri = "";
        #endregion

        var listenerContext = (HttpListenerContext)_listenerContext;
        uri = listenerContext.Request.Url.ToString().Replace(string.Format(":{0}", _port), "");

        // Create Interent Request 
        HttpWebRequest internetRequest = (HttpWebRequest)WebRequest.Create(uri);
        #region Build Request Up
        internetRequest.Method = listenerContext.Request.HttpMethod;
        internetRequest.ProtocolVersion = listenerContext.Request.ProtocolVersion;
        internetRequest.UserAgent = listenerContext.Request.UserAgent;
        foreach (string key in listenerContext.Request.Headers.AllKeys)
        {
            try
            {
                switch (key)
                {
                    case "Proxy-Connection":
                    case "Connection":
                        internetRequest.KeepAlive = (listenerContext.Request.Headers[key].ToLower() == "keep-alive") ? true : false;
                        break;

                    case "Content-Length":
                        internetRequest.ContentLength = listenerContext.Request.ContentLength64;
                        break;

                    case "Content-Type":
                        internetRequest.ContentType = listenerContext.Request.ContentType;
                        break;

                    case "Accept":
                        internetRequest.Accept = listenerContext.Request.Headers[key];
                        break;

                    case "Host":
                        break;

                    case "Referer":
                        internetRequest.Referer = listenerContext.Request.Headers[key];
                        break;

                    case "If-Modified-Since":
                        internetRequest.IfModifiedSince = DateTime.Parse(listenerContext.Request.Headers[key]);
                        break;

                    default:
                        internetRequest.Headers.Add(key, listenerContext.Request.Headers[key]);
                        break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error settup up psRequest object. Error = " + ex.Message + "\n" + ex.StackTrace);
            }
        }
        #endregion

        #region Copy content into request
        buffer = new byte[1024];
        using (Stream instream = listenerContext.Request.InputStream)
        {
            int incount = instream.Read(buffer, 0, buffer.Length);
            while (incount > 0)
            {
                internetRequest.GetRequestStream().Write(buffer, 0, incount);
                incount = instream.Read(buffer, 0, buffer.Length);
            }
        }
        #endregion

        // Get Internet Response
        HttpWebResponse internetResponse = null;
        try
        {
            using (internetResponse = (HttpWebResponse)internetRequest.GetResponse())
            {
                #region Configure Local Response Header Keys
                foreach (string key in internetResponse.Headers.Keys)
                {
                    try
                    {
                        switch (key)
                        {
                            case "Transfer-Encoding":
                                listenerContext.Response.SendChunked = (internetResponse.Headers[key].ToLower() == "chunked") ? true : false;
                                break;

                            case "Content-Length":
                                listenerContext.Response.ContentLength64 = internetResponse.ContentLength;
                                break;

                            case "Content-Type":
                                listenerContext.Response.ContentType = internetResponse.Headers[key];
                                break;

                            case "Keep-Alive":
                                listenerContext.Response.KeepAlive = true;
                                break;

                            default:
                                listenerContext.Response.Headers.Add(key, internetResponse.Headers[key]);
                                break;
                        }
                    }
                    catch (Exception ex)
                    {
                        log("ERROR", uri, "Error settup up listenerContext.Response objects. Error = " + ex.Message + "\n" + ex.StackTrace);
                    }
                }
                #endregion

                try
                {
                    // Transfer the body data from Internet Response to Internal Response
                    buffer = new byte[1024];
                    using (Stream inputStream = internetResponse.GetResponseStream())
                    {
                        int outcount = inputStream.Read(buffer, 0, buffer.Length);
                        while (outcount > 0)
                        {
                            listenerContext.Response.OutputStream.Write(buffer, 0, outcount);
                            outcount = inputStream.Read(buffer, 0, buffer.Length);
                        }
                    }
                }
                catch (Exception ex)
                {
                    log("ERROR", uri, "Could not obtain response from URI: " + ex.Message);
                }
                finally
                {
                    listenerContext.Response.OutputStream.Close();
                }
            }
        }
        catch (Exception ex)
        {
            //if (ex is InvalidOperationException ||
            //    ex is ProtocolViolationException ||
            //    ex is WebException)
            //{
            //    log(uri, "Could not successfully get response: " + ex.GetType() + " - " + ex.Message);
            //    listenerContext.Response.Close();
            //    return;
            //}
            //else { throw; }

            log("ERROR", uri, "Could not successfully get response: " + ex.GetType() + " - " + ex.Message);
            listenerContext.Response.Close();
        }
    }
}

И вот пример того, что я вижу - первый удар хорош, второй имеет ошибку ...

Proxy Started. Press Any Key To Stop...
2080 - INFO (http://newsimg.bbc.co.uk:8080/css/screen/1_0_16/nol/v4/story.css): START - [50]
2080 - INFO (http://newsimg.bbc.co.uk:8080/css/screen/1_0_16/nol/v4/story.css): START - [50]
2080 - ERROR (http://newsimg.bbc.co.uk/css/screen/1_0_16/nol/v4/story.css): Could not successfully get response: System.Net.WebException - The remote server returned an error: (304) Not Modified.

Ответы [ 4 ]

81 голосов
/ 09 апреля 2010

Во-первых, это не ошибка. 3xx обозначает перенаправление. Настоящие ошибки: 4xx (ошибка клиента) и 5xx (ошибка сервера).

Если клиент получает 304 Not Modified, то клиент несет ответственность за отображение рассматриваемого ресурса из своего собственного кэша. В общем, прокси не должен беспокоиться об этом. Это просто посланник.

19 голосов
/ 06 апреля 2015

Это предполагаемое поведение.

Когда вы делаете HTTP-запрос, сервер обычно возвращает код 200 OK. Если вы установите If-Modified-Since, сервер может вернуть 304 Not modified (и ответ не будет иметь содержимого). Это должно быть вашей подсказкой, что страница не была изменена.

Авторы класса по глупости решили , что 304 следует рассматривать как ошибку и выдать исключение. Теперь вам нужно убирать за ними, перехватывая исключение каждый раз, когда вы пытаетесь использовать If-Modified-Since.

14 голосов
/ 04 августа 2017

Простое нажатие F5 не всегда работает.

почему

Потому что ваш провайдер также кеширует данные для вас.

Решение: Force Refresh.

Принудительно обновите ваш браузер, нажав CTRL + F5 в Firefox или Chrome, чтобы тоже очистить кеш интернет-провайдера, вместо простого нажатия F5

В браузере можно увидеть ответ 200 вместо 304 F12 вкладка "Инструменты разработчика".

Еще один прием - добавить знак вопроса ? в конце строки URL запрашиваемой страницы:

http://localhost:52199/Customers/Create?

Знак вопроса гарантирует, что браузер обновит запрос без кэширования каких-либо предыдущих запросов.

Дополнительно в Visual Studio вы можете установить браузер по умолчанию на Chrome в режиме Incognito , чтобы избежать проблем с кэшем при разработке, добавив Chrome в режиме Incognito как браузер по умолчанию, см. шаги (как показано на рисунке):

Go to browsers list Select browse with... Click Add... Point to the chrome.exe on your platform, add argument Choose the browser you just added and set as default, then click browse

0 голосов
/ 23 марта 2017

Я думаю, что вы не установили эти функции. см. ниже на рисунке.

enter image description here

Я тоже страдал от этой проблемы несколько дней назад. После установки этой функции я решил ее. Если вы не установили эту функцию, установите ее.

Процесс установки:

  1. иди в андроид студию
  2. Инструменты
  3. Android
  4. SDK Manager
  5. Внешний вид и поведение
  6. Android SDK
...