首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 模擬表單提交與檔案上傳完整解決方案(含跨域代理)

     編輯:ASP.NET 基礎

當需要跨域上傳資料並取得回應時,瀏覽器同源策略會阻擋直接存取 iframe 回傳內容。最佳做法是在自有網站建立代理頁面:前端提交至代理,代理再用 WebClient 或 HttpWebRequest 轉發至遠端伺服器,繞過跨域限制。

純文字表單提交(application/x-www-form-urlencoded)

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);
    // 處理回應...
}

混合表單(文字欄位 + 檔案)— multipart/form-data 完整構造

此情況需手動組裝符合 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;
                }
            }
        }
    }
}

WinForms 客戶端呼叫範例

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);
}

關鍵點總結

  • Boundary 唯一性:用時間戳或 GUID 產生,避免與檔案內容衝突。
  • Header 格式:每個 part 以 \r\n\r\n 分隔標頭與內容,part 之間以 \r\n 分隔。
  • 結束標記:最後必須加上 --boundary--\r\n。
  • 編碼一致性:全程使用 UTF-8,確保中文檔名、欄位值不亂碼。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved