我正在尝试发布到定义为的网络表单:
<form name="frmdata" method='post' enctype ='multipart/form-data' action ="http://www.rzp.cz/cgi-bin/aps_cacheWEB.sh">
<input type ="hidden" name ="VSS_SERV" value="ZVWSBJXML">
<input type="file" name="filename">
<input type ='submit' name ='x' value ='ODESLI'>
</form>
Run Code Online (Sandbox Code Playgroud)
这里的表格上有一些附加文档:
http://www.rzp.cz/docs/RZP02_XML_28.pdf
我最近的尝试:
using (WebClient client = new WebClient())
{
NameValueCollection vals = new NameValueCollection();
vals.Add("VSS_SERV", "ZVWSBJXML");
string filecontent = @"<?xml version=""1.0"" encoding=""ISO-8859-2""?>";
filecontent = filecontent + @"
<VerejnyWebDotaz
elementFormDefault=""qualified""
targetNamespace=""urn:cz:isvs:rzp:schemas:VerejnaCast:v1""
xmlns=""urn:cz:isvs:rzp:schemas:VerejnaCast:v1"" version=""2.8"">";
filecontent = filecontent + @"
<Kriteria>
<IdentifikacniCislo>03358437</IdentifikacniCislo>
<PlatnostZaznamu>0</PlatnostZaznamu></Kriteria>";
filecontent = filecontent + @"</VerejnyWebDotaz>";
vals.Add("filename", filecontent);
client.Headers["ContentType"] = "multipart/form-data";
byte[] responseArray = client.UploadValues(@"http://www.rzp.cz/cgi-bin/aps_cacheWEB.sh", "POST", vals);
string str = Encoding.ASCII.GetString(responseArray);
}
Run Code Online (Sandbox Code Playgroud)
但我无法克服这个错误:
<KodChyby>-1</KodChyby>(xml文件名不包含命名空间定义的xml)
我如何将此 xml 数据发送到表单,或者更确切地说,有一个工作表单 - http://stuff.petrovsky.cz/subdom/stuff/RZP/rzp-test-form.php - 如何调用和捕获 xml 数据?我想做同样的请求并获取 xml。
使用System.Net.Http我能够构建表单请求作为概念证明MultipartFormDataContent
现在,最初当我测试它时,我收到了 403 Forbidden 响应,但我猜测考虑到我的位置,这是预期的,并且端点可能被区域锁定。
\n原始 Fiddler 响应
\nHTTP/1.1 403 Forbidden\nDate: Sat, 27 Oct 2018 01:37:09 GMT\nServer: IIS\nContent-Length: 225\nKeep-Alive: timeout=5, max=100\nConnection: Keep-Alive\nContent-Type: text/html; charset=iso-8859-1\n\n<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n<html><head>\n<title>403 Forbidden</title>\n</head><body>\n<h1>Forbidden</h1>\n<p>You don\'t have permission to access /cgi-bin/aps_cacheWEB.sh\non this server.</p>\n</body></html>\nRun Code Online (Sandbox Code Playgroud)\n我错了,禁止似乎是错误请求的默认响应,因为您评论说您从该区域内收到了相同的禁止错误。所以我又回到了绘图板。
\n然后,我在本地复制了示例 HTML 表单,然后继续比较表单中的请求(实际上确实有效)和我的代码。逐渐进行更改以匹配我终于能够得到响应200 OK,但响应正文是空的。
显然,如果内容类型标头用引号引起来,服务器在解释内容类型标头中的边界时会出现问题boundary="..."。
经过更多调整后,它开始根据生成的内容配置返回消息。
\nHTTP/1.1 200 OK\nDate: Sat, 27 Oct 2018 19:55:11 GMT\nServer: IIS\nSerial: 10.145\nKeep-Alive: timeout=5, max=100\nConnection: Keep-Alive\nContent-Type: text/plain; charset=ISO-8859-2\nContent-Length: 169\n\nMultiple definitions of VSS_SERV encountered in input.\n If you\'re trying to do this intentionally (such as with select),\n the variable must have a "List" suffix.\nRun Code Online (Sandbox Code Playgroud)\n事实证明,XML API 期望请求采用非常特定的格式。偏离此要求,请求就会失败。
\n未正确生成请求MultipartFormDataContent,这导致服务器无法按预期运行。其他标头放置在部件的 Content-Disposition 标头之前,并且 Content-Disposition 参数也没有用引号引起来。因此,通过不将内容类型包含在部件中并确保正确生成内容处置标头,最终解决了问题。
请务必注意标题添加到内容的顺序,以便Content-Disposition首先为每个部分设置标题。
以所需格式生成请求并获取 XML 数据的工作代码。
\n[Test]\npublic async Task Post_Form() {\n //Arrange\n var stream = getXml();\n var fileContent = new StreamContent(stream);\n fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {\n Name = @"""filename""",\n FileName = @"""req-details.xml""",\n };\n fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/xml");\n \n var stringContent = new ByteArrayContent(Encoding.UTF8.GetBytes("ZVWSBJXML"));\n stringContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {\n Name = @"""VSS_SERV""",\n };\n //could have let system generate it but wanteed to rule it out as a problem\n var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);\n var form = new MultipartFormDataContent(boundary);\n //FIX: boundary quote issue\n var contentType = form.Headers.ContentType.Parameters.First(o => o.Name == "boundary");\n contentType.Value = contentType.Value.Replace("\\"", String.Empty);\n form.Add(stringContent);\n form.Add(fileContent);\n\n //var data = await form.ReadAsStringAsync(); //FOR TESTING PORPOSES ONLY!!\n\n var client = createHttpClient("http://www.rzp.cz/");\n\n //Act\n var response = await client.PostAsync("cgi-bin/aps_cacheWEB.sh", form);\n var body = await response.Content.ReadAsStringAsync();\n\n //Assert\n response.IsSuccessStatusCode.Should().BeTrue();\n body.Should().NotBeEmpty();\n var document = XDocument.Parse(body); //should be valid XML\n document.Should().NotBeNull();\n}\nRun Code Online (Sandbox Code Playgroud)\n上面的代码生成了以下请求,我使用 fiddler 提取了该请求(请密切注意工作格式)
\n[Test]\npublic async Task Post_Form() {\n //Arrange\n var stream = getXml();\n var fileContent = new StreamContent(stream);\n fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {\n Name = @"""filename""",\n FileName = @"""req-details.xml""",\n };\n fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/xml");\n \n var stringContent = new ByteArrayContent(Encoding.UTF8.GetBytes("ZVWSBJXML"));\n stringContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {\n Name = @"""VSS_SERV""",\n };\n //could have let system generate it but wanteed to rule it out as a problem\n var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);\n var form = new MultipartFormDataContent(boundary);\n //FIX: boundary quote issue\n var contentType = form.Headers.ContentType.Parameters.First(o => o.Name == "boundary");\n contentType.Value = contentType.Value.Replace("\\"", String.Empty);\n form.Add(stringContent);\n form.Add(fileContent);\n\n //var data = await form.ReadAsStringAsync(); //FOR TESTING PORPOSES ONLY!!\n\n var client = createHttpClient("http://www.rzp.cz/");\n\n //Act\n var response = await client.PostAsync("cgi-bin/aps_cacheWEB.sh", form);\n var body = await response.Content.ReadAsStringAsync();\n\n //Assert\n response.IsSuccessStatusCode.Should().BeTrue();\n body.Should().NotBeEmpty();\n var document = XDocument.Parse(body); //should be valid XML\n document.Should().NotBeNull();\n}\nRun Code Online (Sandbox Code Playgroud)\n从而能够得到如下的响应。
\nPOST http://www.rzp.cz/cgi-bin/aps_cacheWEB.sh HTTP/1.1\nUser-Agent: System.Net.Http.HttpClient\nAccept-Language: en-US, en; q=0.9\nAccept: text/xml, application/xml\nCache-Control: max-age=0\nContent-Type: multipart/form-data; boundary=---------------------------8d63c301f3e044f\nHost: www.rzp.cz\nContent-Length: 574\nAccept-Encoding: gzip, deflate\nConnection: Keep-Alive\n\n-----------------------------8d63c301f3e044f\nContent-Disposition: form-data; name="VSS_SERV"\n\nZVWSBJXML\n-----------------------------8d63c301f3e044f\nContent-Disposition: form-data; name="filename"; filename="req-details.xml"\nContent-Type: text/xml\n\n<?xml version="1.0" encoding="iso-8859-2"?>\n<VerejnyWebDotaz xmlns="urn:cz:isvs:rzp:schemas:VerejnaCast:v1" version="2.8">\n <Kriteria>\n <IdentifikacniCislo>75848899</IdentifikacniCislo>\n <PlatnostZaznamu>0</PlatnostZaznamu>\n </Kriteria>\n</VerejnyWebDotaz>\n-----------------------------8d63c301f3e044f--\nRun Code Online (Sandbox Code Playgroud)\n从这里开始,根据需要解析生成的 XML 应该是一件小事。
\n生成或加载表单的 XML 流
\nprivate static Stream getXml() {\n var xml = @"<?xml version=""1.0"" encoding=""ISO-8859-2""?>\n<VerejnyWebDotaz \nxmlns=""urn:cz:isvs:rzp:schemas:VerejnaCast:v1"" \nversion=""2.8"">\n<Kriteria> \n <IdentifikacniCislo>75848899</IdentifikacniCislo> \n <PlatnostZaznamu>0</PlatnostZaznamu>\n</Kriteria>\n</VerejnyWebDotaz>";\n var doc = XDocument.Parse(xml);//basically to validate XML\n var stream = new MemoryStream();\n doc.Save(stream);\n stream.Position = 0;\n return stream;\n}\nRun Code Online (Sandbox Code Playgroud)\n在找到有效的匹配后,逐渐能够减少成功请求所需的标头。尝试逐步删除其他代码,以测试是否可以安全地删除更多代码,以减少所需的不必要代码量。
\nprivate static HttpClient createHttpClient(string baseAddress) {\n var handler = createHandler();\n var client = new HttpClient(handler);\n client.BaseAddress = new Uri(baseAddress);\n client.DefaultRequestHeaders.Accept.Clear();\n client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "System.Net.Http.HttpClient");\n client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Language", "en-US,en;q=0.9");\n client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "text/xml,application/xml");\n client.DefaultRequestHeaders.ExpectContinue = false;\n client.DefaultRequestHeaders.ConnectionClose = false;\n client.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue() {\n MaxAge = TimeSpan.FromSeconds(0)\n };\n return client;\n}\n\nprivate static HttpClientHandler createHandler() {\n var handler = new HttpClientHandler();\n // if the framework supports automatic decompression set automatic decompression\n if (handler.SupportsAutomaticDecompression) {\n handler.AutomaticDecompression = System.Net.DecompressionMethods.GZip |\n System.Net.DecompressionMethods.Deflate;\n }\n return handler;\n}\nRun Code Online (Sandbox Code Playgroud)\n当我选择使用异步API时System.Net.Http,我发现了类似的问题
通过 WebClient 引用带有 POST 值的UploadFile
\n使用完成的答案WebClient可以适应您的问题,以便可以构建类似于上面生成的请求。
我也尝试测试那个,但遇到了同样的禁止错误。既然知道了正确的格式,您还应该能够使用正确地制作工作请求WebClient/WebRequest