Почему я получаю сообщение об ошибке "(304)" Не изменено "на некоторых ссылках при использовании HttpWebRequest?
Любые идеи, почему на некоторых ссылках, которые я пытаюсь получить с помощью HttpWebRequest, я получаю "Удаленный сервер возвратил ошибку: (304) Не изменено". в коде?
Код, который я использую, это Jeff post here (страница, похоже, исчезла, см. архивная копия на 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 ссылку, у которой есть проблема, и, похоже, она работает нормально, второй раз она получает ошибку, 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 body
List<byte> responseBody = new List<byte>(); // Byte array to hold the response 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.
Ответы
Ответ 1
Во-первых, это не ошибка. 3xx
обозначает перенаправление. Реальные ошибки 4xx
(ошибка клиента) и 5xx
(ошибка сервера).
Если клиент получает 304 Not Modified
, то это ответственность клиента за отображение рассматриваемого вопроса из его собственного кеша. В общем, прокси не должен беспокоиться об этом. Это просто посланник.
Ответ 2
Это предполагаемое поведение.
Когда вы делаете HTTP-запрос, сервер обычно возвращает код 200 OK
. Если вы установите If-Modified-Since
, сервер может вернуть 304 Not modified
(и ответ не будет содержать контент). Это должно быть вашим сигналом, что страница не была изменена.
авторы этого класса глупо решили, что 304
следует рассматривать как ошибку и вызывать исключение. Теперь вам нужно очистить их, поймав исключение каждый раз, когда вы пытаетесь использовать If-Modified-Since
.
Ответ 3
Простое нажатие F5 не всегда работает.
Зачем?
Потому что ваш провайдер также кеширует веб-данные для вас.
Решение: принудительное обновление.
Принудительно обновите ваш браузер, нажав CTRL + F5 в Firefox или Chrome, чтобы очистить кеш интернет-провайдера, вместо того, чтобы просто нажать F5
Затем вы можете увидеть ответ 200 вместо 304 во вкладке сети инструментов разработчика F12.
Еще один трюк - добавить знак вопроса ?
в конце строки URL запрашиваемой страницы:
http://localhost:52199/Customers/Create?
Вопросительный знак гарантирует, что браузер обновит запрос без кеширования любых предыдущих запросов.
Кроме того, в Visual Studio вы можете установить браузер по умолчанию в Chrome в режиме инкогнито, чтобы избежать проблем с кэшем при разработке, добавив Chrome в режиме инкогнито в качестве браузера по умолчанию, см. Шаги (как показано на рисунке):
![Choose the browser you just added and set as default, then click browse]()
Ответ 4
Я думаю, что вы не установили эти функции. см. ниже на рисунке.
![enter image description here]()
Я также страдал от этой проблемы несколько дней назад. После установки этой функции я решил ее. Если вы не установили эту функцию, установите ее.
Процесс установки:
- перейти в студию android studio
- Инструменты
- Android
- Менеджер SDK
- Внешний вид и поведение
- Android SDK