Почему я получаю сообщение об ошибке "(304) Not Modified" в некоторых ссылках при использовании HttpWebRequest?
Любые идеи, почему по некоторым ссылкам, к которым я пытаюсь получить доступ с помощью 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-й раз OK, 4-й раз ошибка, 5-й OK и т. Д. Как будто есть какое-то состояние, которое не очищается или что-то в коде. Я попытался немного очистить код, используя операторы типа "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.
5 ответов
Во-первых, это не ошибка. 3xx
обозначает перенаправление. Настоящие ошибки 4xx
(ошибка клиента) и 5xx
(Ошибка сервера).
Если клиент получает 304 Not Modified
тогда клиент несет ответственность за отображение рассматриваемого ресурса из своего собственного кэша. В общем, прокси не должен беспокоиться об этом. Это просто посланник.
Это намеренное поведение.
Когда вы делаете HTTP-запрос, сервер обычно возвращает код 200 OK
, Если вы установите If-Modified-Since
сервер может вернуться 304 Not modified
(и в ответе не будет содержания). Это должно быть вашей подсказкой, что страница не была изменена.
Авторы класса по глупости решили, что 304
следует рассматривать как ошибку и выдать исключение. Теперь вы должны убирать за ними, ловя исключение каждый раз, когда вы пытаетесь использовать If-Modified-Since
,
Просто нажатие F5 не всегда работает.
Зачем?
Потому что ваш провайдер также кеширует веб-данные для вас.
Решение: принудительное обновление.
Принудительно обновите ваш браузер, нажав CTRL + F5 в Firefox или Chrome, чтобы очистить кеш интернет-провайдера, вместо того, чтобы просто нажимать F5
Затем вы можете увидеть ответ 200 вместо 304 во вкладке сети инструментов разработчика F12 браузера.
Еще одна хитрость - добавить знак вопроса. ?
в конце строки URL запрашиваемой страницы:
http://localhost:52199/Customers/Create?
Вопросительный знак будет гарантировать, что браузер обновит запрос без кэширования любых предыдущих запросов.
Это не проблема, это из-за кэширования...
Чтобы преодолеть это, добавьте метку времени к вызову конечной точки, например
axios.get('/api/products')
.
После метки времени должно быть
axios.get(/api/products?${Date.now()}
.
Это разрешит ваш код состояния 304 .
Я думаю, что вы не установили эти функции. смотрите ниже на картинке.
Я также страдал от этой проблемы несколько дней назад. После установки этой функции я решил ее. Если вы не установили эту функцию, установите ее.
Процесс установки:
- пойти в андроид студию
- инструменты
- Android
- SDK Manager
- Внешний вид и поведение
- Android SDK