當需要跨域上傳資料並取得回應時,瀏覽器同源策略會阻擋直接存取 iframe 回傳內容。最佳做法是在自有網站建立代理頁面:前端提交至代理,代理再用 WebClient 或 HttpWebRequest 轉發至遠端伺服器,繞過跨域限制。
string uri = "https://localhost/login.aspx";
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
string postData = "Username=admin&Password=admin";
byte[] requestBytes = Encoding.ASCII.GetBytes(postData);
byte[] responseBytes = client.UploadData(uri, "POST", requestBytes);
// 處理 responseBytes...
}
string uri = "https://localhost/uploadFile.aspx";
using (var client = new WebClient())
{
string filePath = @"C:/upload.txt";
byte[] responseBytes = client.UploadFile(uri, "POST", filePath);
// 處理回應...
}
此情況需手動組裝符合 RFC 2046 的 multipart 內容,關鍵在於正確設定 boundary 與 Content-Type:
using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
namespace UploadProxy
{
public class MultipartFormBuilder
{
private readonly Encoding _encoding = Encoding.UTF8;
private readonly ArrayList _parts = new ArrayList();
private string _boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
public string ContentType => $"multipart/form-data; boundary={_boundary}";
/// 加入一般文字欄位
public void AddField(string name, string value)
{
string header = $"{_boundary}\r\nContent-Disposition: form-data; name=\"{name}\"\r\n\r\n{value}\r\n";
_parts.Add(_encoding.GetBytes(header));
}
/// 加入檔案欄位
public void AddFile(string name, string fileName, string contentType, byte[] fileBytes)
{
string header = $"{_boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{fileName}\"\r\nContent-Type: {contentType}\r\n\r\n";
byte[] headerBytes = _encoding.GetBytes(header);
byte[] tailBytes = _encoding.GetBytes("\r\n");
byte[] part = new byte[headerBytes.Length + fileBytes.Length + tailBytes.Length];
Buffer.BlockCopy(headerBytes, 0, part, 0, headerBytes.Length);
Buffer.BlockCopy(fileBytes, 0, part, headerBytes.Length, fileBytes.Length);
Buffer.BlockCopy(tailBytes, 0, part, headerBytes.Length + fileBytes.Length, tailBytes.Length);
_parts.Add(part);
}
/// 組裝完整請求體(含結束 boundary)
public byte[] Build()
{
string endBoundary = $"{_boundary}--\r\n";
_parts.Add(_encoding.GetBytes(endBoundary));
int totalLen = 0;
foreach (byte[] b in _parts) totalLen += b.Length;
byte[] result = new byte[totalLen];
int offset = 0;
foreach (byte[] b in _parts)
{
Buffer.BlockCopy(b, 0, result, offset, b.Length);
offset += b.Length;
}
return result;
}
/// 發送並取得回應
public bool Submit(string url, out byte[] response)
{
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", ContentType);
try
{
response = client.UploadData(url, "POST", Build());
return true;
}
catch (WebException ex)
{
using (var respStream = ex.Response.GetResponseStream())
{
response = new byte[ex.Response.ContentLength];
respStream.Read(response, 0, response.Length);
}
return false;
}
}
}
}
}
private void btnUpload_Click(object sender, EventArgs e)
{
if (!File.Exists(txtFilePath.Text)) { MessageBox.Show("檔案不存在"); return; }
byte[] fileBytes = File.ReadAllBytes(txtFilePath.Text);
var builder = new MultipartFormBuilder();
builder.AddField("FileName", txtFileName.Text);
builder.AddField("AmigoToken", txtToken.Text);
builder.AddFile("FileData", Path.GetFileName(txtFilePath.Text), "application/octet-stream", fileBytes);
byte[] response;
bool ok = builder.Submit("https://localhost/UploadData/UploadAvatar.aspx", out response);
txtResponse.Text = Encoding.UTF8.GetString(response);
}
\r\n\r\n 分隔標頭與內容,part 之間以 \r\n 分隔。--boundary--\r\n。