【发布时间】:2014-02-26 05:26:26
【问题描述】:
ServiceStack 会忽略 Accept 标头的任何原因?该服务托管在 ASP.NET 应用程序中,并在 IDE 中以调试方式运行。使用 System.Web.WebRequest 对象对服务的前 40 次左右调用会导致服务正确响应。大约 50 次调用后,客户端检测到 404 错误(服务中未命中断点)。从那时起,Accept 标头将被忽略。所有后续请求始终返回 XML。
正在使用的客户端...
var client = (HttpWebRequest)WebRequest.Create(uri);
client.Method = WebRequestMethods.Http.Post;
client.AllowWriteStreamBuffering = false;
client.SendChunked = true;
client.ContentType = "multipart/form-data;";
client.Timeout = int.MaxValue; // HACK:REMOVE
client.Accept = "application/json";
现在调用有点乱(尝试调试失败)...
using (FileStream fileStream = File.OpenRead(filePaths[i]))
{
fileStream.Copy(client.GetRequestStream());
}
var responseString = string.Empty;
try { responseString = new StreamReader(client.GetResponse().GetResponseStream()).ReadToEnd(); }
catch (Exception ex) { Debug.WriteLine(ex.Message); }
if (String.IsNullOrWhiteSpace(responseString)) { continue; }
PutFileResponse response = null;
try { response = responseString.FromJson<PutFileResponse>(); }
catch (Exception ex) { Debug.WriteLine(ex.Message); }
if (response == null)
{
try { response = responseString.FromXml<PutFileResponse>(); }
catch (Exception ex) { Debug.WriteLine(ex.Message); }
if (response == null)
{
continue;
}
}
我保持原样显示响应。前 50 个(大约)调用按请求返回 JSON。在 404 之后所有后续调用总是返回 XML。
有什么想法吗?
编辑(2014-02-25 10:35 EST):
看了 Fiddler 之后,这比我想象的要奇怪。在 559 个请求中,有 34 个导致 404 错误。但是,该服务在错误之前和之后继续响应而没有问题。 404 错误是第一个令人费解的部分。第二项(XML 和 JSON 之间的切换不那么令人费解,但也很奇怪。
该应用程序是一个文件存储应用程序,并且正在递归测试目录以将文件推送到服务。它遇到的一些文件是实际的 XML 文件。所有文件都在 Stream 中发送,嵌套在 DTO 中,客户端为每个请求添加“application/json”的 Accept 标头。如果发送 XML 文件,即使已发送 Accept 标头,服务也会以 XML 响应。
示例请求标头(会话 94):
POST
http://localhost:50205/Files/Put/8178F94DBDBC4AB18F42118AFD01D1A2/AA10C004D624DA892171F8A7E8CD8D05/201760/ServiceStack.xml HTTP/1.1
Content-Type: multipart/form-data;
Accept: application/json
Host: localhost:50205
Transfer-Encoding: chunked
Expect: 100-continue
1000
<?xml version="1.0"?>
<doc>
[SNIP]
</doc>
0
示例响应标头(会话 #94):
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/xml
Server: Microsoft-IIS/8.0
X-Powered-By: ServiceStack/4.011 Win32NT/.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcX1NvdXJjZVxGSUwwMVx0cnVua1xTcG90bGVzc1xGcmFtZXdvcmtzXEZpbGVNYW5hZ2VtZW50XFByb2plY3RzXEZNRi5TdG9yYWdlU2VydmVyLkhvc3RpbmcuUHVibGljXEZpbGVzXFB1dFw4MTc4Rjk0REJEQkM0QUIxOEY0MjExOEFGRDAxRDFBMlxBQTEwQzAwNEQ2MjREQTg5MjE3MUY4QTdFOENEOEQwNVwyMDE3NjBcU2VydmljZVN0YWNrLnhtbA==?=
X-Powered-By: ASP.NET
Date: Tue, 25 Feb 2014 15:19:06 GMT
Content-Length: 563
<?xml version="1.0" encoding="utf-8"?><PutFileResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/FMF.StorageServer.Services.Messages.Files"><ResponseStatus xmlns:d2p1="http://schemas.servicestack.net/types" i:nil="true" /><Status><FileSignature><Checksum>AA10C004D624DA892171F8A7E8CD8D05</Checksum><SizeBytes>201760</SizeBytes></FileSignature><IsAvailable i:nil="true" /><IsKnown i:nil="true" /><IsOnDisk i:nil="true" /><IsSuccessful i:nil="true" /><StatusMessage i:nil="true" /></Status></PutFileResponse>
不幸的是,我必须在将每个文件发送到服务器之前检测其内部结构,并且永远无法信任文件扩展名。要么就是这样,要么总是假设服务器可能会在我没想到的时候决定发回 XML。
一个更紧迫的问题是为什么仅对部分请求检测到 404 错误。在 559 个请求中,产生 404 错误的项目是 77、232、235、238、246、275 等......所以服务或客户端只是在随机请求上失败。
编辑(2014-02-25 12:20 EST):
似乎所有失败的文件(404 错误)都是基于文本的。比如……
示例请求标头(会话 #560):
POST http://localhost:50205/Files/Put/060C976372174F51BEB84FE524E57C57/1931975CE8E1090A6D66738A560888AD/1426/AssemblyInfo.cs HTTP/1.1
Content-Type: multipart/form-data;
Accept: application/json
Host: localhost:50205
Transfer-Encoding: chunked
Expect: 100-continue
592
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Utility")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Utility")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1071992e-2d4c-49df-9526-6d4d29f979b4")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
0
示例响应标头(会话 #560):
HTTP/1.1 404 Not Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?RDpcX1NvdXJjZVxGSUwwMVx0cnVua1xTcG90bGVzc1xGcmFtZXdvcmtzXEZpbGVNYW5hZ2VtZW50XFByb2plY3RzXEZNRi5TdG9yYWdlU2VydmVyLkhvc3RpbmcuUHVibGljXEZpbGVzXFB1dFwwNjBDOTc2MzcyMTc0RjUxQkVCODRGRTUyNEU1N0M1N1wxOTMxOTc1Q0U4RTEwOTBBNkQ2NjczOEE1NjA4ODhBRFwxNDI2XEFzc2VtYmx5SW5mby5jcw==?=
X-Powered-By: ASP.NET
Date: Tue, 25 Feb 2014 15:24:10 GMT
Connection: close
Content-Length: 5106
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>IIS 8.0 Detailed Error - 404.7 - Not Found</title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana,Arial,Helvetica,sans-serif;}
code{margin:0;color:#006600;font-size:1.1em;font-weight:bold;}
.config_source code{font-size:.8em;color:#000000;}
pre{margin:0;font-size:1.4em;word-wrap:break-word;}
ul,ol{margin:10px 0 10px 5px;}
ul.first,ol.first{margin-top:5px;}
fieldset{padding:0 15px 10px 15px;word-break:break-all;}
.summary-container fieldset{padding-bottom:5px;margin-top:4px;}
legend.no-expand-all{padding:2px 15px 4px 10px;margin:0 0 0 -12px;}
legend{color:#333333;;margin:4px 0 8px -12px;_margin-top:0px;
font-weight:bold;font-size:1em;}
a:link,a:visited{color:#007EFF;font-weight:bold;}
a:hover{text-decoration:none;}
h1{font-size:2.4em;margin:0;color:#FFF;}
h2{font-size:1.7em;margin:0;color:#CC0000;}
h3{font-size:1.4em;margin:10px 0 0 0;color:#CC0000;}
h4{font-size:1.2em;margin:10px 0 5px 0;
}#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS",Verdana,sans-serif;
color:#FFF;background-color:#5C87B2;
}#content{margin:0 0 0 2%;position:relative;}
.summary-container,.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
.content-container p{margin:0 0 10px 0;
}#details-left{width:35%;float:left;margin-right:2%;
}#details-right{width:63%;float:left;overflow:hidden;
}#server_version{width:96%;_height:1px;min-height:1px;margin:0 0 5px 0;padding:11px 2% 8px 2%;color:#FFFFFF;
background-color:#5A7FA5;border-bottom:1px solid #C1CFDD;border-top:1px solid #4A6C8E;font-weight:normal;
font-size:1em;color:#FFF;text-align:right;
}#server_version p{margin:5px 0;}
table{margin:4px 0 4px 0;width:100%;border:none;}
td,th{vertical-align:top;padding:3px 0;text-align:left;font-weight:normal;border:none;}
th{width:30%;text-align:right;padding-right:2%;font-weight:bold;}
thead th{background-color:#ebebeb;width:25%;
}#details-right th{width:20%;}
table tr.alt td,table tr.alt th{}
.highlight-code{color:#CC0000;font-weight:bold;font-style:italic;}
.clear{clear:both;}
.preferred{padding:0 5px 2px 5px;font-weight:normal;background:#006633;color:#FFF;font-size:.8em;}
-->
</style>
</head>
<body>
<div id="content">
<div class="content-container">
<h3>HTTP Error 404.7 - Not Found</h3>
<h4>The request filtering module is configured to deny the file extension.</h4>
</div>
<div class="content-container">
<fieldset><h4>Most likely causes:</h4>
<ul> <li>Request filtering is configured for the Web server and the file extension for this request is explicitly denied.</li> </ul>
</fieldset>
</div>
<div class="content-container">
<fieldset><h4>Things you can try:</h4>
<ul> <li>Verify the configuration/system.webServer/security/requestFiltering/fileExtensions settings in applicationhost.config and web.config.</li> </ul>
</fieldset>
</div>
<div class="content-container">
<fieldset><h4>Detailed Error Information:</h4>
<div id="details-left">
<table border="0" cellpadding="0" cellspacing="0">
<tr class="alt"><th>Module</th><td> RequestFilteringModule</td></tr>
<tr><th>Notification</th><td> BeginRequest</td></tr>
<tr class="alt"><th>Handler</th><td> ServiceStack.Factory</td></tr>
<tr><th>Error Code</th><td> 0x00000000</td></tr>
</table>
</div>
<div id="details-right">
<table border="0" cellpadding="0" cellspacing="0">
<tr class="alt"><th>Requested URL</th><td> http://localhost:50205/Files/Put/060C976372174F51BEB84FE524E57C57/1931975CE8E1090A6D66738A560888AD/1426/AssemblyInfo.cs</td></tr>
<tr><th>Physical Path</th><td> D:\_Source\FIL01\trunk\Spotless\Frameworks\FileManagement\Projects\FMF.StorageServer.Hosting.Public\Files\Put\060C976372174F51BEB84FE524E57C57\1931975CE8E1090A6D66738A560888AD\1426\AssemblyInfo.cs</td></tr>
<tr class="alt"><th>Logon Method</th><td> Not yet determined</td></tr>
<tr><th>Logon User</th><td> Not yet determined</td></tr>
<tr class="alt"><th>Request Tracing Directory</th><td> C:\Users\Fred\Documents\IISExpress\TraceLogFiles\FMF.STORAGESERVER.HOSTING.PUBLIC</td></tr>
</table>
<div class="clear"></div>
</div>
</fieldset>
</div>
<div class="content-container">
<fieldset><h4>More Information:</h4>
This is a security feature. Do not change this feature unless the scope of the change is fully understood. If the file extension for the request should be allowed, remove the denied file extension from configuration/system.webServer/security/requestFiltering/fileExtensions.
<p><a href="http://go.microsoft.com/fwlink/?LinkID=62293&IIS70Error=404,7,0x00000000,9200">View more information »</a></p>
</fieldset>
</div>
</div>
</body>
</html>
编辑(2014-02-25 14:27 EST):
继续测试并发现忽略 Accept 标头的 ServiceStack 是一个比我希望的更大的问题。由于必须保留所有文件,并且这些文件必须同时包含 HTML 和 XML 文件,因此我需要确保 ServiceStack 只发回请求的响应。我上次测试中发送的一些文件包括 HTML 文件,很遗憾,ServiceStack 发回了一个 HTML 文档作为响应。
临时文件夹包含一堆随机文件。而且,正如您所料,由于我手头有大量源文件,临时文件夹包含一些 C#/VS2K12 解决方案。例如,我复制了 DoFactory 解决方案的源代码,它的几个 .Config、.cs、.csproj 文件失败,而其他同类型的文件通过。
正在使用的 DTO...
//[Route("/Files/Put/{Token}/{Checksum}/{SizeBytesText}/{FileNameOrExtension}", "POST")]
[Route("/Files/Put/{PathInfo*}", "POST")]
public class PutFileRequest : IReturn<PutFileResponse>, IRequiresRequestStream
{
public string Token { get; set; }
public string Checksum { get; set; }
public string SizeBytesText { get; set; }
public string FileNameOrExtension { get; set; }
public System.IO.Stream RequestStream { get; set; }
}
我故意包含了我使用的原始路线。请注意,URI 是使用一组变量和文件名构造的。文件的名称是为了方便在服务器上使用,以允许使用原始文件扩展名持久化文件。
以下是来自测试应用程序的 Main 方法,该方法始终失败。任何发布此文件的尝试都会导致 404 错误。 请注意,文件是完整的,并且 FileSteam 能够成功打开和复制文件的内容。如果文件存在问题,那么这应该会失败。
static void Main(string[] args)
{
var filePath = @"D:\Temp\_Source\DoFactory\CS_4.5\Spark\Art.Web\Areas\Shop\Models\ProductsModel.cs";
var fileInfo = Files.GetInfo(filePath, calculateChecksum: true);
var uri = @"http://localhost:50205/Files/Put/" +
Guid.NewGuid().ToString("N") + "/" +
fileInfo.Checksum + "/" +
fileInfo.SizeBytes.Value + "/" +
System.IO.Path.GetFileName(filePath);
var client = (HttpWebRequest) WebRequest.Create(uri);
client.Method = WebRequestMethods.Http.Post;
client.AllowWriteStreamBuffering = false;
client.SendChunked = true;
client.ContentType = "multipart/form-data;";
client.Timeout = int.MaxValue;
client.Accept = "application/json";
using (FileStream fileStream = File.OpenRead(filePath))
{
fileStream.CopyTo(client.GetRequestStream());
}
var responseString = string.Empty;
try { responseString = new StreamReader(client.GetResponse().GetResponseStream()).ReadToEnd(); }
catch (Exception ex) { Debug.WriteLine(ex.Message); }
if (String.IsNullOrWhiteSpace(responseString)) { Environment.Exit(1); }
PutFileResponse response = null;
try { response = responseString.FromJson<PutFileResponse>(); }
catch (Exception ex) { Debug.WriteLine(ex.Message); }
if (response == null)
{
try { response = responseString.FromXml<PutFileResponse>(); }
catch (Exception ex) { Debug.WriteLine(ex.Message); }
}
if (response == null)
{
try { response = responseString.FromJsv<PutFileResponse>(); }
catch (Exception ex) { Debug.WriteLine(ex.Message); }
}
if (response == null) { Environment.Exit(2); }
Console.ReadLine();
}
【问题讨论】:
-
能否提供原始的 HTTP 请求和 HTTP 响应,因为它从 JSON 变为 XML?
标签: servicestack