实践总结
本次基于对500错误定位为例,给大家讲解整个分析过程与解决方法。
1.本次实践为HTTP错误状态码定位提供一个高效、精确的定位方式,不仅仅局限于500错误。
2.针对500错误本身,可以基于问题出现频率和下述经验值将问题进行归类,缩小定位范围。
问题描述1:单个调用接口返回500错误。
分析过程
1、 首先,弄清什么是“HTTP请求状态码500”?
(1)500 (Internal Server Error)是内部服务器错误。
(2)500 (SC_INTERNAL_SERVER_ERROR) 是常用的“服务器错误”状态。该状态经常由CGI程序引起。也可能由无法正常运行的或返回头信息格式不正确的servlet引起。
2、其次,如何捕获异常信息?
(1)通常我们使用WebException进行捕获,代码示例如下:
try{…}
catch (WebException ex)
{
HttpWebResponse resp = (HttpWebResponse)ex.Response;
Stream receiveStream = resp.GetResponseStream();
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
StreamReader readStream = new StreamReader(receiveStream, encode);
Char[] read = new Char[256];
int count = readStream.Read(read, 0, 256);
while (count > 0)
{
output += new String(read, 0, count);
count = readStream.Read(read, 0, 256);
}
readStream.Close();
resp.Close();
}
(2)通常我们会发现我们捕获到的内容如下:
权限问题 标记的“mode”属性设置为“Off”。
说明: 服务器上出现应用程序错误。此应用程序的当前自定义错误设置禁止查看应用程序错误的详细信息。
详细信息: 若要使他人能够从本地服务器计算机上查看此特定错误信息的详细信息,请在位于当前 Web 应用程序根目录下的“web.config”配置文件中创建一个 标记。然后应将此 标记的“mode”属性设置为“RemoteOnly”。若要使他人能够在远程计算机上查看详细信息,请将“mode”设置为“Off”。
由于我们更多情况下是远程调用接口,所以需在web.config文件中做如下配置:
<!-- Web.Config 配置文件 -->
<configuration>
<system.web>
<customErrors mode="Off"/>
</system.web>
</configuration>
获取IIS日志查看权限后,基于第(1)种方法再次捕获内容如下:
…从客户端中检测到有潜在危险的Request.Form值…
.Net中,Request时如果出现有HTML或Javascript等字符串时,系统会认为是危险性值,触发System.Web.HttpRequestValidationException异常,提示信息大概如下:
异常信息: System.Web.HttpRequestValidationException: 从客户端……中检测到有潜在危险的 Request.Form 值。
说明: 请求验证过程检测到有潜在危险的客户端输入值,对请求的处理已经中止。该值可能指示危及应用程序安全的尝试,如跨站点的脚本攻击。通过在 Page 指令或 配置节中设置 validateRequest=false 可以禁用请求验证。但是,在这种情况下,强烈建议应用程序显式检查所有输入。
解决方法
解决办法1
在.aspx文件头中加入以下语句:
<configuration>
<system.web>
<pages validateRequest="false" />
</system.web>
</configuration>
备注:若基于.NET 2.0版本可以使用上述配置。若基于.NET 4.0版本,则配置如下:
<system.web>
<httpRuntime requestValidationMode="2.0" />
<pages validateRequest="false"/>
</system.web>
解决办法3
此方法不需要置validateRequest=false
在当前页面添加Page_Error()函数,来捕获页面处理过程中发生的而没有处理的异常。然后给用户一个合理的提示信息。
如果当前页面没有Page_Error(),这个异常将会送到Global.asax的Application_Error()来处理,你也可以在那里写通用的异常报错处理函数。
如果两个地方都没有写异常处理函数,才会显示这个默认的报错页面。
代码示例如下:
protected void Page_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpRequestValidationException)
{
Response.Write("请您输入合法字符串。");
Server.ClearError(); // 如果不ClearError()这个异常会继续传到Application_Error()。
}}
推荐使用:方法3
推荐理由:在不以牺牲IIS安全性为前提去解决现有问题
问题描述2:单个调用接口返回200,当并发调用返回500。
分析过程
与上述一致,但捕获到的内容为:
System.IO.IOException: 文件“E:va2013031510.log”正由另一进程使用,因此该进程无法访问该文件。
备注:大多数情况下,问题2不是一开始就产生,而是并发调用一段时间后才出现。
解决方法
使用共享锁,赋予文件读和写权限,代码示例如下:
FileStream fs = new FileStream(url, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader sr = new StreamReader(fs, System.Text.Encoding.Default);