緣起:
前幾天在處理專案 (WebForm),有個下戴 excel
的功能需要調整,它是用 window.location 來指定 ashx,用 get 帶參數,然後 ashx
再依參數來回傳 excel 檔。
這個功能碰上的問題是,get
帶的參數有時會太長,超過限制
情境:
我這邊新增一個叫 WebApplication1 的
WebForm 來示範,專案裡有 birdshiutest.aspx 跟 DownloadTxt.ashx。
birdshiutest.aspx,cs
檔沒有寫額外的程式,所以就不展示出來了
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="birdshiutest.aspx.cs" Inherits="WebApplication1.birdshiutest" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<script type="text/javascript">
function DownloadTxt() {
window.location.href = '/DownloadTxt.ashx?param1=hello¶m2=test¶m3=yes';
}
</script>
<form id="form1" runat="server">
<div>
<button onclick="DownloadTxt(); return false;">下載txt</button>
</div>
</form>
</body>
</html>
這是 DownloadTxt.ashx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace WebApplication1
{
/// <summary>
/// DownloadTxt 的摘要描述
/// </summary>
public class DownloadTxt : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string sParam1 = context.Request.QueryString.Get("param1");
string sParam2 = context.Request.QueryString.Get("param2");
string sParam3 = context.Request.QueryString.Get("param3");
StringBuilder sbResult = new StringBuilder();
sbResult.AppendLine($"參數 1 : {sParam1}");
sbResult.AppendLine($"參數 2 : {sParam2}");
sbResult.AppendLine($"參數 3 : {sParam3}");
context.Response.Clear();
context.Response.Buffer = false;
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.Charset = "UTF-8";
context.Response.ContentType = "text/plain";
context.Response.AppendHeader("Content-Disposition", $"attachment;filename=download.txt");
context.Response.Write(sbResult.ToString());
context.Response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
把 birdshiutest.aspx 跑起來,進到頁面後,點擊 "下載txt"
的按鈕,就能載 txt
改成用 Post:
首先,要修改 DownloadTxt.ashx,主要是修 17~19
行,把 context.Request.QueryString.Get 改成 context.Request.Form.Get。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace WebApplication1
{
/// <summary>
/// DownloadTxt 的摘要描述
/// </summary>
public class DownloadTxt : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string sParam1 = context.Request.Form.Get("param1");
string sParam2 = context.Request.Form.Get("param2");
string sParam3 = context.Request.Form.Get("param3");
StringBuilder sbResult = new StringBuilder();
sbResult.AppendLine($"參數 1 : {sParam1}");
sbResult.AppendLine($"參數 2 : {sParam2}");
sbResult.AppendLine($"參數 3 : {sParam3}");
context.Response.Clear();
context.Response.Buffer = false;
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.Charset = "UTF-8";
context.Response.ContentType = "text/plain";
context.Response.AppendHeader("Content-Disposition", $"attachment;filename=download.txt");
context.Response.Write(sbResult.ToString());
context.Response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
再來是 birdshiutest.aspx 頁面,這個要怎麼改呢 ? window.location.href 只能傳網址參數而已,用 ajax 嗎
? 如果是用 ajax 呼叫取得回傳值,那又要怎麼開啟下載的頁面 ?
感覺不太好做,所以我後來就再看看有什麼其它的方法,最後是找到這個。它是動態產生一個 form 的 dom 物件,然後把要傳的值打包成 type="hidden"
的 input,放到 form 裡,然後把 from 掛到網頁 body 的後面,最後呼叫 form 的
submit function 來傳送表單。
所以,我們 birdshiutest.aspx 的程式碼可以改成
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="birdshiutest.aspx.cs" Inherits="WebApplication1.birdshiutest" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<script type="text/javascript">
function postForm(path, params, method = 'post') {
const form = document.createElement('form');
form.method = method;
form.action = path;
for (const key in params) {
if (params.hasOwnProperty(key)) {
const hiddenField = document.createElement('input');
hiddenField.type = 'hidden';
hiddenField.name = key;
hiddenField.value = params[key];
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
function DownloadTxt() {
postForm('/DownloadTxt.ashx', {
param1: 'hello',
param2: 'test',
param3: 'yes'
});
}
</script>
<form id="form1" runat="server">
<div>
<button onclick="DownloadTxt(); return false;">下載txt</button>
</div>
</form>
</body>
</html>
一樣打開 birdshiutest.aspx 頁面,然後點擊按鈕,能成功下載 txt 檔
每次點 button,body 就都會加上一個 form,感覺不是很健康,所以可以再修改一下那個 postForm 的 function,改成 submit 完後過個 5 秒,就呼叫 remove 方法來把表格移除。
沒有留言:
張貼留言