web-dev-qa-db-fra.com

Pourquoi ai-je l'erreur "(304) Not Modified" sur certains liens lors de l'utilisation de HttpWebRequest?

Toutes les idées sur lesquelles je tente d'accéder à l'aide de HttpWebRequest sur certains liens que j'obtiens "Le serveur distant a renvoyé une erreur: (304) non modifié." dans le code?

Le code que j'utilise provient de le post de Jeff ici (la page semble avoir disparu, voir un copie d'archive à la Wayback Machine ).

Notez que le concept du code est un simple serveur proxy. Je pointe donc mon navigateur vers ce morceau de code exécuté localement, qui obtient la demande de mon navigateur, puis le proxie en créant un nouveau HttpWebRequest, comme vous le verrez dans le code. Cela fonctionne très bien pour la plupart des sites/liens, mais pour certains cette erreur se produit. Vous verrez qu'un élément clé du code est l'endroit où il semble copier les paramètres d'en-tête http de la demande du navigateur vers sa demande sur le site, et les attributs d'en-tête sont copiés. Vous ne savez pas si le problème est lié à la façon dont il reproduit cet aspect de la demande et que se passe-t-il alors que le résultat revient?

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

Je reçois le problème par exemple de http://en.wikipedia.org/wiki/Main_Page

PS. UPDATE ICI

Ça ne marche toujours pas. En gros, je peux identifier un lien qui a un problème, et cela semble fonctionner correctement, la deuxième fois que l'erreur est obtenue, la troisième fois, OK, la quatrième fois, l'erreur, la cinquième fois, etc. Comme s'il y avait un état qui n'était pas effacé ou quelque chose dans le code. J'ai essayé de nettoyer un peu le code en utilisant "using", etc.

Voici le code. Si quelqu'un peut comprendre pourquoi chaque deuxième fois, je navigue vers un lien tel que http://newsimg.bbc.co.uk/css/screen/1_0_16/nol/v4/story.css (en commençant par le 2ème fois, pas la première) via ce code proxy, j'obtiens l'erreur que j'aimerais entendre.

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();
        }
    }
}

Et voici un exemple de ce que je vois - le premier coup est bon, le deuxième a une erreur ...

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.
42
Greg

Tout d'abord, ce n'est pas une erreur. Le 3xx indique une redirection. Les vraies erreurs sont 4xx (erreur du client) et 5xx (erreur du serveur).

Si un client obtient un 304 Not Modified , le client est responsable d'afficher la ressource en question à partir de son propre cache. En général, le proxy ne devrait pas s'inquiéter de cela. C'est juste le messager.

82
BalusC

Ceci est le comportement prévu.

Lorsque vous faites une requête HTTP, le serveur renvoie normalement le code 200 OK. Si vous définissez If-Modified-Since, le serveur peut renvoyer 304 Not modified (et la réponse n'aura pas le contenu). Ceci est censé être votre indice que la page n'a pas été modifiée.

Les les auteurs de la classe ont bêtement décidé que 304 devrait être traité comme une erreur et renvoyer une exception. Maintenant, vous devez nettoyer après eux en interceptant l'exception à chaque fois que vous essayez d'utiliser If-Modified-Since.

19
Superbest

Juste en appuyant F5 ne fonctionne pas toujours.

pourquoi?

Parce que votre FAI met également en cache des données Web pour vous.

Solution: Forcer l'actualisation.

Forcez l'actualisation de votre navigateur en appuyant sur CTRL + F5 dans Firefox ou Chrome pour effacer le cache du FAI aussi, au lieu de simplement appuyer sur F5

Vous pouvez alors voir 200 réponses au lieu de 304 dans le navigateur F12 onglet réseau des outils de développement.

Une autre astuce consiste à ajouter un point d'interrogation ? à la fin de la chaîne d’URL de la page demandée:

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

Le point d'interrogation garantit que le navigateur actualise la demande sans mettre en cache les demandes précédentes.

En outre, dans Visual Studio , vous pouvez définir le navigateur par défaut sur . Chrome dans Mode Incognito pour éviter les problèmes de cache lors du développement, en ajoutant Chrome en mode Incognito en tant que navigateur par défaut, reportez-vous à la illustré):

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

14
Ashraf Abusada