问题描述
|
我想使用.net 2.0从浏览器窗口(或Webbrowser-instance)中的C#WinForm应用程序中进行POST到PHP站点,我需要正确获取数据和headers-argments。喜欢:
webbrowser1.Navigate(\"http://mypublishservice.com/publish_picture.PHP\",\"_SELF\",X,Y);
问题是:X和Y应该是什么?我知道必须将所有标头和文件数据填充到byte []数组中,并添加一些其他标头作为字符串。我在下面制作了Webform的示例,并使用Firebug对其进行了检查。所以我知道POST数据应该是什么样子。我什至创建了一个可以的HttpWebRequest,但是我需要一个Webbrowser(下面的原因)来启动Post-Request。所以我迷路了。我尝试了很多选择,例如使用HTTPWebrequest(多部分/表单数据)上传文件。通过创建HttpWebrequest并将其传递给Webbrowser-instance或类似的方法,也许是一种更好的方法?
这是一个可以正常运行publish_picture.PHP页面的Web表单:
<!DOCTYPE html>
<html>
<head>
<title></title>
<Meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">
</head>
<body>
<div>
<form enctype=\"multipart/form-data\" action=\"http://mypublishservice.com/publish_picture.PHP\" method=\"POST\">
Please choose a photo:
<input name=\"source\" type=\"file\"><br/><br/>
Say something about this photo:
<input name=\"message\" type=\"text\" value=\"\"><br/><br/>
<input type=\"submit\" value=\"Upload\"/><br/>
</form>
</div>
</body>
</html>
如果您问我为什么要这样做,这里有一些想法可以捍卫我的愚蠢决定;)
为什么是Webbrowser实例而不是简单的HttpWebrequest?因为目标服务(例如Facebook)需要(或似乎需要)适当的浏览器!
为什么不使用目标服务API(例如Facebook API)?结果发现,桌面Web通讯不好(太多的400错误)。
更新2:
看起来更好。仍然出现错误,但可能是PHP页面本身。这是您要记住的吗?
public static byte[] PrepareUploadFiles(string address,IEnumerable<UploadFile> files,NameValueCollection values,out string header)
{
using (var requestStream = new MemoryStream())
{
var boundary = \"---------------------------\" + DateTime.Now.Ticks.ToString(\"x\"); //,NumberFormatInfo.InvariantInfo);
header = \"multipart/form-data; boundary=\" + boundary;
var boundaryBuffer2 = Encoding.ASCII.GetBytes(header);
requestStream.Write(boundaryBuffer2,boundaryBuffer2.Length);
boundary = \"--\" + boundary;
// Write the values
foreach (string name in values.Keys)
{
var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
requestStream.Write(buffer,buffer.Length);
buffer = Encoding.ASCII.GetBytes(string.Format(\"Content-disposition: form-data; name=\\\"{0}\\\"{1}{1}\",name,Environment.NewLine));
requestStream.Write(buffer,buffer.Length);
buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
requestStream.Write(buffer,buffer.Length);
}
// Write the files
foreach (var file in files)
{
var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
requestStream.Write(buffer,buffer.Length);
buffer = Encoding.UTF8.GetBytes(string.Format(\"Content-disposition: form-data; name=\\\"{0}\\\"; filename=\\\"{1}\\\"{2}\",file.Name,file.Filename,buffer.Length);
buffer = Encoding.ASCII.GetBytes(string.Format(\"Content-Type: {0}{1}{1}\",file.ContentType,buffer.Length);
copyStream(file.Stream,requestStream); // file.Stream.copyTo(requestStream);
buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
requestStream.Write(buffer,buffer.Length);
}
var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + \"--\");
requestStream.Write(boundaryBuffer,boundaryBuffer.Length);
return requestStream.ToArray();
}
}
public static void copyStream(Stream input,Stream output)
{
byte[] buffer = new byte[32768];
while (true)
{
int read = input.Read(buffer,buffer.Length);
if (read <= 0)
return;
output.Write(buffer,read);
}
}
public void Upload()
{
using (var stream1 = File.Open(Support.EXAMPLEIMAGE,FileMode.Open))
{
var files = new[]
{
new UploadFile
{
Name = \"source\",// 1
Filename = Support.EXAMPLEIMAGE,ContentType = \"image/jpeg\",// 2
Stream = stream1
}
};
var values = new NameValueCollection
{
{ \"message\",\"a text\" } // 3
};
string contentType; // 4. do I need it
byte[] dataToPost = Support.PrepareUploadFiles(Support.URL,files,values,out contentType); // 5. out contentType = what should be the result vaule?
//PrepareUploadFiles(url,out contentType);
webbrowser1.Navigate(Support.URL,null,dataToPost,\"Content-Type: \" + contentType + Environment.NewLine);
}
}
解决方法
我个人喜欢使用ParseQueryString方法,因为它可以正确编码参数:
var values = HttpUtility.ParseQueryString(string.Empty);
values[\"param1\"] = \"param1 value\";
values[\"param2\"] = \"param2 value\";
values[\"param3\"] = \"param3 value\";
var dataToPost = Encoding.UTF8.GetBytes(values.ToString());
var url = \"http://mypublishservice.com/publish_picture.php\";
var contentType = \"Content-Type: application/x-www-form-urlencoded\" + Environment.NewLine;
webBrowser1.Navigate(url,null,dataToPost,contentType);
现在,由于您正在尝试上传文件,因此这将变得有些困难。我写了一篇博客文章,阐述了如何生成允许上传多个文件的“ 4”请求。因此,您可以调整此处显示的UploadFiles方法,使其仅返回POST正文,而不进行实际的上传,然后执行以下操作:
string contentType;
byte[] dataToPost = PrepareUploadFiles(url,files,values,out contentType);
webBrowser1.Navigate(url,\"Content-Type: \" + contentType + Environment.NewLine);