TL; DR版本

当写入请求流时发生传输错误时,即使服务器发送,也无法访问响应.

完整版

我有一个.NET应用程序,使用HttpWebRequest将文件上传到Tomcat服务器.在某些情况下,服务器提前关闭请求流(因为它由于某种原因拒绝文件,例如文件名无效),并发送具有自定义标头的400响应以指示错误的原因.

问题是,如果上传的文件很大,请求流在我完成编写请求正文之前关闭,我得到一个IOException:

Message: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.
InnerException: SocketException: An existing connection was forcibly closed by the remote host

我可以捕获这个异常,但是当我调用GetResponse时,我得到一个WebException,其中以前的IOException作为它的内部异常,并且返回一个空的Response属性.所以我无法得到响应,即使服务器发送它(使用WireShark检查).

由于我无法得到答复,我不知道实际的问题是什么.从我的应用程序的角度来看,它看起来像是连接被中断,所以我把它当作一个网络相关的错误,并重试上传…当然,再次失败.

如何解决这个问题并从服务器检索实际响应?甚至有可能吗对我来说,目前的行为看起来像HttpWebRequest中的一个bug,或至少是一个严重的设计问题…

这是我用来重现问题的代码:

var request = HttpWebRequest.CreateHttp(uri);
request.Method = "POST";
string filename = "foo\u00A0bar.dat"; // Invalid characters in filename,the server will refuse it
request.Headers["Content-disposition"] = string.Format("attachment; filename*=utf-8''{0}",Uri.EscapeDataString(filename));
request.AllowWriteStreamBuffering = false;
request.ContentType = "application/octet-stream";
request.ContentLength = 100 * 1024 * 1024;

// Upload the "file" (just random data in this case)
try
{
    using (var stream = request.GetRequestStream())
    {
        byte[] buffer = new byte[1024 * 1024];
        new Random().NextBytes(buffer);
        for (int i = 0; i < 100; i++)
        {
            stream.Write(buffer,buffer.Length);
        }
    }
}
catch(Exception ex)
{
    // here I get an IOException; InnerException is a SocketException
    Console.WriteLine("Error writing to stream: {0}",ex);
}

// Now try to read the response
try
{
    using (var response = (HttpWebResponse)request.GetResponse())
    {
        Console.WriteLine("{0} - {1}",(int)response.StatusCode,response.StatusDescription);
    }
}
catch(Exception ex)
{
    // here I get a WebException; InnerException is the IOException from the prevIoUs catch
    Console.WriteLine("Error getting the response: {0}",ex);
    var webEx = ex as WebException;
    if (webEx != null)
    {
        Console.WriteLine(webEx.Status); // SendFailure
        var response = (HttpWebResponse)webEx.Response;
        if (response != null)
        {
            Console.WriteLine("{0} - {1}",response.StatusDescription);
        }
        else
        {
            Console.WriteLine("No response");
        }
    }
}

补充笔记:

如果我正确地了解100继续状态的作用,服务器不应该将其发送给我,如果它将拒绝该文件.但是,似乎这个状态是由Tomcat直接控制的,不能被应用程序所控制.在这种情况下,理想情况下,我希望服务器不要送我100继续,但是根据我的后台负责人的介绍,没有简单的方法.所以我现在正在寻找一个客户端解决方案;但是如果您碰巧知道如何解决服务器端的问题,那么也不胜感激.

我遇到问题的应用程序针对.NET 4.0,但是我也用4.5转载.

我不会超时异常在超时之前抛出很久.

我尝试了异步请求.它没有改变任何东西.

我尝试将请求协议版本设置为HTTP 1.0,结果相同.

其他人已经在Connect问题上提交了一个错误:https://connect.microsoft.com/VisualStudio/feedback/details/779622/unable-to-get-servers-error-response-when-uploading-file-with-httpwebrequest

解决方法

关于什么可以是客户端解决您的问题,我是不明智的.但是我仍然认为使用自定义tomcat阀门的服务器端解决方案可以在此帮助.我目前没有一个tomcat安装程序,我可以测试这个,但我认为这里的服务器端解决方案将如下:

RFC第8.2.3节明确规定:
HTTP / 1.1原始服务器的要求:

- Upon receiving a request which includes an Expect request-header
    field with the "100-continue" expectation,an origin server MUST
    either respond with 100 (Continue) status and continue to read
    from the input stream,or respond with a final status code. The
    origin server MUST NOT wait for the request body before sending
    the 100 (Continue) response. If it responds with a final status
    code,it MAY close the transport connection or it MAY continue
    to read and discard the rest of the request.  It MUST NOT
    perform the requested method if it returns a final status code.

所以假设tomcat确认到RFC,而在自定义阀门中,您将收到HTTP请求头,但是请求主体不会被发送,因为控件尚未在读取主体的servlet中.

所以你可以实现一个自定义阀门,类似于:

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ErrorReportValve;

public class CustomUploadHandlerValve extends ValveBase {

    @Override
    public void invoke(Request request,Response response) throws IOException,servletexception {
         HttpServletRequest httpRequest = (HttpServletRequest) request;
         String fileName = httpRequest.getHeader("Filename");  // get the filename or whatever other parameters required as per your code
         bool validationSuccess = Validate(); // perform filename check or anyother validation here
         if(!validationSuccess)
         {
             response = CreateResponse(); //create your custom 400 response here
             request.SetResponse(response);
             // return the response here
         }
         else
         {
             getNext().invoke(request,response); // to pass to the next valve/ servlet in the chain
         }
    }
    ...
}

免责声明:再次,我没有尝试这个成功,需要一些时间和一个tomcat安装程序来尝试;).以为这可能是你的起点.

c# – 如何在请求流在传输过程中关闭时获取HTTP响应的更多相关文章

  1. 关于h5中的fetch方法解读(小结)

    这篇文章主要介绍了关于h5中的fetch方法解读(小结),fetch身为H5中的一个新对象,他的诞生,是为了取代ajax的存在而出现,有兴趣的可以了解一下

  2. ios – 使用NSURLSession获取JSON数据

    我试图从谷歌距离api使用NSURLSession获取数据,但如下所示,当我打印响应和数据时,我得到的结果为NULL.可能是什么问题?

  3. ios – 错误域= com.alamofire.error.serialization.response代码= -1011“请求失败:禁止

    任何人都可以帮我解决以下错误–>在AFNetworking2.5中使用“删除”方法时出错解决方法我发现,如果我的手机时钟不同步……它不允许我更新…也许检查你的手机设置到正确的时间“自动区”,看看是否有效…

  4. iOS网页/原生应用Facebook登录弹出 – 失败?

    如果我重新启动app/web-app,用户将自动登录,并重定向到成功页面.我认为是导致问题的原因当您在Firefox/Chrome/Safari浏览器中运行网页时,Facebook登录对话框会弹出一个弹出窗口或另一个选项卡.我相信这是这个弹出页面的一个问题,以及当成功登录时Javascript如何与自身通信.window.close的东西没有返回的根页面…失败的解决方法由于应用程序挂在前面提到的URL上,我决定在shouldStartLoadWithRequest(…)中添加if语句以强制UIWebvie

  5. 通过AFNetworking 2.0上传iOS图像

    我一直在寻找新的AFNetworking2.0上传图像的例子.但是我正在撞墙,无法弄清楚代码有什么问题.所以这是我使用的代码TIA解决方法我最终使用了多部分请求

  6. ios – 在Objective-C中发送分块的HTTP 1.1请求

    我有以下问题:我正在创建一个非常大的SOAP请求(数据是一个编码为Base64字符串的视频),因此我不能将其作为原始SOAP请求发送,而是需要在HTTP1.1块中发送它.我似乎无法弄明白该怎么做.我在这里使用了代码:WhatarealternativestoNSURLConnectionforchunkedtransferencoding但它似乎没有做我认为应该做的事情–我可以看到请求作为单个请求

  7. ios – Watchkit新会话不起作用

    我的手表扩展中有两个视图控制器.每当我打电话时我只得到第一个视图控制器的响应,并在第二个viewcontroller中得到错误WCSession在app和watch扩展中启动.任何建议?

  8. 使用Firebase iOS Swift将特定设备的通知推送到特定设备

    我非常感谢PushNotifications的帮助.我的应用聊天,用户可以直接向对方发送短信.但是如果没有PushNotifications,它就没有多大意义.它全部设置在Firebase上.如何将推送通知从特定设备发送到特定设备?

  9. ios – 保存从查询中获取的用户的属性(即不在currentUser上)

    我有兴趣根据currentUser执行的操作将属性保存到数据库中的用户.基于以下代码,我收到错误消息“除非已通过logIn或signUp验证用户,否则无法保存用户”我想知道是否有一个解决方法,我可以将属性保存到foundUser,而无需登录该用户.谢谢你的帮助!解决方法如果要更新当前不是登录用户的用户,则需要使用主密钥调用Parse.您可以从CloudCode执行此操作;并从您的iOS项目中调用它;

  10. 在iOS中使用NSJSONSerialization进行JSON解析

    解决方法首先在您的JSON响应字典中,在“RESPONSE”键下,您有一个数组而不是字典,该数组包含字典对象.所以要提取用户名和电子邮件ID,如下所示

随机推荐

  1. c# – (wpf)Application.Current.Resources vs FindResource

    所以,我正在使用C#中的WPF创建一个GUI.它看起来像这样:它现在还没有完成.这两行是我尝试制作一种数据表,它们在XAML中是硬编码的.现在,我正在C#中实现添加新的水果按钮功能.我在XAML中有以下样式来控制行的背景图像应该是什么样子:因此,在代码中,我为每列col0,col1和col2创建一个图像,如果我使用以下代码,它添加了一个如下所示的新行:如你所见,它不太正确……为什么一个似乎忽略了一些属性而另一个没有?

  2. c# – 绑定DataGridTemplateColumn

    似乎我已经打了个墙,试图在DataGrid上使用DataTemplates.我想要做的是使用一个模板来显示每个单元格的两行文本.但是似乎无法以任何方式绑定列.以下代码希望显示我想做的事情.注意每个列的绑定:模板列没有这样的东西,因此,这个xaml不可能工作.我注定要将整个DataTemplate复制到每个列,只是对每个副本都有不同的约束?解决方法我不完全确定你想要做什么,但如果您需要获取整行的DataContext,可以使用RelativeSource绑定来移动视觉树.像这样:

  3. c# – 学习设计模式的资源

    最近我来到了这个设计模式的概念,并对此感到非常热情.你能建议一些帮助我深入设计模式的资源吗?

  4. c# – 是否有支持嵌入HTML页面的跨操作系统GUI框架?

    我想开发一个桌面应用程序来使用跨系统,是否有一个GUI框架,允许我为所有3个平台编写一次代码,并具有完全可脚本化的嵌入式Web组件?我需要它有一个API来在应用程序和网页之间进行交流.我知道C#,JavaScript和一些python.解决方法Qt有这样的事情QWebView.

  5. c# – 通过字符串在对象图中查找属性

    我试图使用任意字符串访问嵌套类结构的各个部分.给出以下(设计的)类:我想要从Person对象的一个实例的“PersonsAddress.HousePhone.Number”获取对象.目前我正在使用反思来做一些简单的递归查找,但是我希望有一些忍者有更好的想法.作为参考,这里是我开发的(crappy)方法:解决方法您可以简单地使用标准的.NETDataBinder.EvalMethod,像这样:

  6. c# – 文件下载后更新页面

    FamilyID=0a391abd-25c1-4fc0-919f-b21f31ab88b7&displaylang=en&pf=true它呈现该页面,然后使用以下元刷新标签来实际向用户提供要下载的文件:你可能需要在你的应用程序中做类似的事情.但是,如果您真的有兴趣在文件完全下载后执行某些操作,那么您的运气不佳,因为没有任何事件可以与浏览器进行通信.执行此操作的唯一方法是上传附件时使用的AJAXupload.

  7. c# – 如何在每个机器应用程序中实现单个实例?

    我必须限制我的.net4WPF应用程序,以便每台机器只能运行一次.请注意,我说每个机器,而不是每个会话.我使用一个简单的互斥体实现单实例应用程序,直到现在,但不幸的是,这样一个互斥是每个会话.有没有办法创建机器互连,还是有其他解决方案来实现每个机器应用程序的单个实例?

  8. c# – WCF和多个主机头

    我的雇主网站有多个主机名,都是同一个服务器,我们只是显示不同的皮肤来进行品牌宣传.不幸的是,在这种情况下,WCF似乎不能很好地工作.我试过overridingthedefaulthostwithacustomhostfactory.这不是一个可以接受的解决方案,因为它需要从所有主机工作,而不仅仅是1.我也看过thisblogpost,但是我无法让它工作,或者不是为了解决我的问题.我得到的错误是“这

  9. c# – ASP.NET MVC模型绑定与表单元素名称中的虚线

    我一直在搜索互联网,试图找到一种方式来容纳我的表单元素的破折号到ASP.NET的控制器在MVC2,3或甚至4中的默认模型绑定行为.作为一名前端开发人员,我更喜欢在我的CSS中使用camelCase或下划线进行破折号.在我的标记中,我想要做的是这样的:在控制器中,我会传入一个C#对象,看起来像这样:有没有办法通过一些正则表达式或其他行为来扩展Controller类来适应这种情况?我讨厌这样的事实,我必须这样做:甚至这个:思考?

  10. c# – 用户界面设计工具

    我正在寻找一个用户界面设计工具来显示文档中可能的GUI.我不能生成代码.我知道MicrosoftVisio提供了一个功能.但有什么办法吗?您使用哪种软件可视化GUI?

返回
顶部