发送到 BinaryWrite() 的超过 4MB 的数据是否应该分块?
Should data exceeding 4MB sent to BinaryWrite() ever be chunked?
我有一些旧代码可以将二进制数据写入 Response 对象的 BinaryWrite() 方法(经典 ASP)。它以 4MB 块的形式将数据发送到 BinaryWrite(),但现在我想知道这是否有效,BinaryWrite() 是否设计用于处理串行数据块(或者它是否应该最多每次调用一次页面请求)。
我发现这个 link 描述了应该如何增加“响应缓冲限制”,增加它似乎已经解决了我看到的问题(根本没有使用我的分块代码)。
https://docs.microsoft.com/en-us/troubleshoot/iis/http-500-response-binarywrite
这是有问题的旧代码:
HRESULT STDMETHODCALLTYPE CQVMActiveHost::WriteData (const VOID* pcvData, DWORD cbData, __out DWORD* pcbWritten)
{
HRESULT hr;
DISPPARAMS dispParams = {0};
VARIANT vWrite = {0}, vResult = {0};
Check(LoadResponseObject());
dispParams.cArgs = 1;
dispParams.rgvarg = &vWrite;
if(m_fSupportsBinary)
{
SAFEARRAYBOUND Bound;
DWORD cbRemaining = cbData;
Bound.lLbound = 0;
vWrite.vt = VT_ARRAY | VT_UI1;
while(0 < cbRemaining)
{
PVOID pbPtr;
Bound.cElements = min(cbRemaining, 4 * 1024 * 1024);
vWrite.parray = SafeArrayCreate(VT_UI1, 1, &Bound);
CheckAlloc(vWrite.parray);
SafeArrayAccessData(vWrite.parray, &pbPtr);
CopyMemory(pbPtr, pcvData, Bound.cElements);
SafeArrayUnaccessData(vWrite.parray);
VariantClear(&vResult);
Check(m_pResponse->Invoke(m_dispidBinaryWrite, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &vResult, NULL, NULL));
SafeArrayDestroy(vWrite.parray);
vWrite.parray = NULL;
pcvData = reinterpret_cast<const BYTE*>(pcvData) + Bound.cElements;
cbRemaining -= Bound.cElements;
}
vWrite.vt = VT_EMPTY;
}
else
我在旧代码中看到了一些不同的行为。在某些测试中,对 BinaryWrite() 的第一次调用成功,但后续调用失败并显示“发生异常”HRESULT。在其他测试中,似乎调用成功,但浏览器没有收到任何数据。
是否存在使用分块数据多次调用 BinaryWrite() 有意义的场景?
或者我是否应该始终将“响应缓冲限制”值增加到 4MB 以上,然后使用完整数据对 BinaryWrite() 进行一次调用?
谢谢!
我想知道我最初写上面代码时Response.Buffer
属性是不是false
。我发现的内容如下:
- 每个页面请求可以多次调用
Response.BinaryWrite()
方法。
- 如果要返回给客户端的数据量很大,那么把数据拆分成多个调用给
Response.BinaryWrite()
。
- IIS 中的“响应缓冲限制”值(ASP)默认为 4MB。
- 如果
Response.Buffer
是 true
,则可能会多次调用 Response.BinaryWrite()
,直到总数据达到“响应缓冲限制”值。此时,必须调用 Response.Flush()
。否则,尝试发送更多数据会导致错误 0x80020009。
- 如果
Response.Buffer
是 false
,则不要调用 Response.Flush()
,而是将数据分成多个(较小的)调用 Response.BinaryWrite()
。
- 例如,我尝试使用多次调用
Response.BinaryWrite()
发送一个 12MB 的文件,每个块为 4MB。启用了缓冲,因此第一次调用成功,但下一次调用失败。将“响应缓冲限制”提高到 16MB“解决”了这个问题,但增加了 ASP. 的缓冲分配
最终,我修改了分块代码以首先查询 Response.Buffer
属性。数据总是以较小的片段发送到 Response.BinaryWrite()
,但如果启用缓冲,也会调用 Response.Flush()
。
最后,不要设置Content-Length
header。浏览器可能不知道将下载多少字节,但它会正确接收文件,而无需手动设置 header。设置 header 中断下载。
最后的 ASP 脚本:
function GoDownloadFile (strPath)
{
var idxName = strrchr(strPath, '/');
var strFolder = left(strPath, idxName + 1);
var strFile = right(strPath, len(strPath) - (idxName + 1));
var oFS = Security.GetChannel().OpenFileSystem();
oFS.Folder = strFolder;
Response.ContentType = Host.GetContentType(strFile);
Response.AddHeader("Content-Disposition", "attachment; FileName=\"" + strFile + "\"");
Host.BinaryWrite(oFS.ReadFile(strFile));
}
我有一些旧代码可以将二进制数据写入 Response 对象的 BinaryWrite() 方法(经典 ASP)。它以 4MB 块的形式将数据发送到 BinaryWrite(),但现在我想知道这是否有效,BinaryWrite() 是否设计用于处理串行数据块(或者它是否应该最多每次调用一次页面请求)。
我发现这个 link 描述了应该如何增加“响应缓冲限制”,增加它似乎已经解决了我看到的问题(根本没有使用我的分块代码)。 https://docs.microsoft.com/en-us/troubleshoot/iis/http-500-response-binarywrite
这是有问题的旧代码:
HRESULT STDMETHODCALLTYPE CQVMActiveHost::WriteData (const VOID* pcvData, DWORD cbData, __out DWORD* pcbWritten)
{
HRESULT hr;
DISPPARAMS dispParams = {0};
VARIANT vWrite = {0}, vResult = {0};
Check(LoadResponseObject());
dispParams.cArgs = 1;
dispParams.rgvarg = &vWrite;
if(m_fSupportsBinary)
{
SAFEARRAYBOUND Bound;
DWORD cbRemaining = cbData;
Bound.lLbound = 0;
vWrite.vt = VT_ARRAY | VT_UI1;
while(0 < cbRemaining)
{
PVOID pbPtr;
Bound.cElements = min(cbRemaining, 4 * 1024 * 1024);
vWrite.parray = SafeArrayCreate(VT_UI1, 1, &Bound);
CheckAlloc(vWrite.parray);
SafeArrayAccessData(vWrite.parray, &pbPtr);
CopyMemory(pbPtr, pcvData, Bound.cElements);
SafeArrayUnaccessData(vWrite.parray);
VariantClear(&vResult);
Check(m_pResponse->Invoke(m_dispidBinaryWrite, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &vResult, NULL, NULL));
SafeArrayDestroy(vWrite.parray);
vWrite.parray = NULL;
pcvData = reinterpret_cast<const BYTE*>(pcvData) + Bound.cElements;
cbRemaining -= Bound.cElements;
}
vWrite.vt = VT_EMPTY;
}
else
我在旧代码中看到了一些不同的行为。在某些测试中,对 BinaryWrite() 的第一次调用成功,但后续调用失败并显示“发生异常”HRESULT。在其他测试中,似乎调用成功,但浏览器没有收到任何数据。
是否存在使用分块数据多次调用 BinaryWrite() 有意义的场景?
或者我是否应该始终将“响应缓冲限制”值增加到 4MB 以上,然后使用完整数据对 BinaryWrite() 进行一次调用?
谢谢!
我想知道我最初写上面代码时Response.Buffer
属性是不是false
。我发现的内容如下:
- 每个页面请求可以多次调用
Response.BinaryWrite()
方法。 - 如果要返回给客户端的数据量很大,那么把数据拆分成多个调用给
Response.BinaryWrite()
。 - IIS 中的“响应缓冲限制”值(ASP)默认为 4MB。
- 如果
Response.Buffer
是true
,则可能会多次调用Response.BinaryWrite()
,直到总数据达到“响应缓冲限制”值。此时,必须调用Response.Flush()
。否则,尝试发送更多数据会导致错误 0x80020009。 - 如果
Response.Buffer
是false
,则不要调用Response.Flush()
,而是将数据分成多个(较小的)调用Response.BinaryWrite()
。 - 例如,我尝试使用多次调用
Response.BinaryWrite()
发送一个 12MB 的文件,每个块为 4MB。启用了缓冲,因此第一次调用成功,但下一次调用失败。将“响应缓冲限制”提高到 16MB“解决”了这个问题,但增加了 ASP. 的缓冲分配
最终,我修改了分块代码以首先查询 Response.Buffer
属性。数据总是以较小的片段发送到 Response.BinaryWrite()
,但如果启用缓冲,也会调用 Response.Flush()
。
最后,不要设置Content-Length
header。浏览器可能不知道将下载多少字节,但它会正确接收文件,而无需手动设置 header。设置 header 中断下载。
最后的 ASP 脚本:
function GoDownloadFile (strPath)
{
var idxName = strrchr(strPath, '/');
var strFolder = left(strPath, idxName + 1);
var strFile = right(strPath, len(strPath) - (idxName + 1));
var oFS = Security.GetChannel().OpenFileSystem();
oFS.Folder = strFolder;
Response.ContentType = Host.GetContentType(strFile);
Response.AddHeader("Content-Disposition", "attachment; FileName=\"" + strFile + "\"");
Host.BinaryWrite(oFS.ReadFile(strFile));
}