如何使用 XMLHttpRequest 和 FormData 对象在 multipart/form-data 上设置我自己的边界

Posted

技术标签:

【中文标题】如何使用 XMLHttpRequest 和 FormData 对象在 multipart/form-data 上设置我自己的边界【英文标题】:How to set my own boundary on multipart/form-data using XMLHttpRequest and FormData object 【发布时间】:2013-01-22 13:16:48 【问题描述】:

在使用 FormData 对象将文件附加到请求时,我一直试图找到一种方法来在 XMLHttpRequest 对象上设置自己的边界。我看过很多关于这个的帖子,每个人都说“不要设置边界,它会自动为你生成。”这不是我想要的。让我解释一下我需要什么,这样我就不会收到这类回复。

我有一个 Web 服务端点,我向该端点发送一个包含两个图像和一些 json 数据的 multipart/form-data 请求。由于 WCF 无法解析多部分请求,因此我使用一些开源代码构建了自己的解析器。它的工作方式是,我定义了一个边界,用于分隔请求的每个部分,从那里开始一切正常。因此,我必须能够将边界设置为服务器代码所期望的,以便我的解析类能够在输入流中找到任何内容。

我知道这是可以做到的,因为我已经使用 Fiddler 做到了这一点,并且一位同事能够在我们正在构建的应用程序中这样做,该应用程序调用我的方法,但我正在尝试使用 Chrome 浏览器应用程序让它工作称为 Postman,它使用 FormData 对象发送多部分请求。除了请求生成自己的边界(通常类似于:

----WebKitFormBoundaryQUWQnB6c7TzNzdcz

最后附加的字符串是随机生成的,所以它永远不会相同,因此我不能使用这个工具来测试我的端点,因为服务器无法知道要寻找什么边界。

我尝试在 Content-Type 标头中设置我的边界,虽然请求显示标头已添加到请求中,但正文仍使用随机边界。

所以问题是如何告诉 FormData 对象和/或 XMLHttpRequest 对象使用我的边界而不是正在生成的随机边界?

我无法想象这是一件不常见的事情,我的意思是到目前为止,我调用使用 multipart/form-data 的服务的所有经验都告诉我在 api 中设置边界的内容,但没有人说“只是不要设置它,我们将使用生成的随机垃圾......”

同样作为视觉效果,这是我在标题中看到的内容:

Request Headers
POST /DHICachet.svc/json/DepositCheck HTTP/1.1
Host: dhiibews.securexfr.com
Connection: keep-alive
Content-Length: 514696
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.11 (Khtml, like Gecko) Chrome/23.0.1271.64 Safari/537.11
Content-Type: multipart/form-data; boundary=myboundary
Cache-Control: no-cache
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: ASP.NET_SessionId=zdepe2nhkz0vbhxiulzc2qq1

Request Payload
------WebKitFormBoundaryQUWQnB6c7TzNzdcz
Content-Disposition: form-data; name="item"; filename="Screen shot 2012-09-03 at 4.00.10 AM.png"
Content-Type: image/png


------WebKitFormBoundaryQUWQnB6c7TzNzdcz--

请注意,即使我的边界在请求标头中设置为myboundary,主体只是将在幕后生成的任何边界放入其中。另请注意,如果我不设置该标头,它只是将其放入里面的随机边界。

【问题讨论】:

【参考方案1】:

这并不能真正回答我的问题,但我确实找到了解决方法。我突然意识到,我实际上可以通过对内容类型标头进行一些字符串数学来检测正在通过的边界。我刚刚在我的代码中添加了以下内容:

string contenttype = _ctx.IncomingRequest.Headers["Content-Type"].ToString();
string boundary = contenttype.Substring(contenttype.IndexOf('=') + 1);

这允许我接受任何调试边界。但是,我仍然需要我们的特定生产边界。

【讨论】:

如果这不能真正回答您的问题,您不应将其标记为答案。我发现这篇文章很有帮助,但不是解决方案。 点了,我会删除答案标签,以防其他人找到其他方法。 FWIW,这是我尝试做的一个可接受的解决方案,我只是不确定我最初想要做的方式实际上是否可行。 你的回答确实给了我一些思考。 (+1)感谢您的努力。希望有人能来提供进一步的见解。【参考方案2】:

我遇到了类似的问题,我在发帖时将内容类型标题设置为undefined 解决了问题...'Content-Type': undefined

我相信浏览器会自动正确处理 FormData 的 POST 并按照您的预期设置 Content-type 标头,包括未设置的边界。所以这意味着服务器上不需要特殊的请求头解析逻辑。

【讨论】:

【参考方案3】:

您可以将文件转换为二进制字符串,然后提交。代码是 TypeScript,但 javascript 类似。

async uploadFile(myFile: File): Promise<boolean> 
        // Get the binary string from the file in order to send the file with `multipart/form-data`
        const contentPromise = new Promise<string>((resolve) => 
            const reader = new FileReader()
            reader.onload = async function (evt) 
                const pdfContent: string = evt?.target?.result as string
                resolve(pdfContent)
            

            reader.readAsBinaryString(myFile)
        )
        const binaryContent = await contentPromise

        // Send the request
        const path = `api/update-file`
        const content = `--WebAppBoundary
Content-Disposition: form-data; name="myFile"; filename="$myFile.name"
Content-Type: application/pdf

$binaryContent
--WebAppBoundary--`

        const requestOptions = 
            method: 'POST',
            headers: 
                'Content-Type': 'multipart/form-data; boundary=WebAppBoundary'
            ,
            body: content
        

        const response:  code: number; message: string  = await (await fetch(path, requestOptions)).json()

        // Return the response
        return response.code === 200
    

【讨论】:

以上是关于如何使用 XMLHttpRequest 和 FormData 对象在 multipart/form-data 上设置我自己的边界的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls

如何在 JavaScript 中使用 XMLHttpRequest 设置 Cookie(标头)?

如何让 Axios 使用 Fetch 而不是 XMLHttpRequest

如何使用 XMLHttpRequest 和 FormData 对象在 multipart/form-data 上设置我自己的边界

如何使用 XMLHttpRequest 进行 zcash rpc 调用

使用formdata时如何在XMLHttpRequest中添加头数据?