首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用NodeJs发布多个二进制文件

用NodeJs发布多个二进制文件
EN

Stack Overflow用户
提问于 2017-06-30 16:01:46
回答 1查看 1.6K关注 0票数 0

如何使用POST只使用 http模块向服务器发送多个二进制文件?

例如,我的钥匙应该是这样的:

代码语言:javascript
复制
{
    Image1: <binary-data>,
    Image2: <binary-data>
}
EN

回答 1

Stack Overflow用户

发布于 2017-07-01 05:54:10

TL:DR;请参阅答案底部的完整示例代码。

我试图弄清楚如何仅使用核心NodeJS模块(不使用类似于POST等的任何东西)将多个二进制图像文件发送到NodeJs中的服务器。在DuckDuckGo上输入错误的搜索词并在网上找不到任何例子大约3个小时后,我就要换个职业了。但是在我的头撞在桌子上将近半天之后,我的紧迫感变得迟钝,我设法想出了一个可行的解决方案。如果没有给这个堆叠溢出柱这个吉特布·吉斯特写答案的好人,这是不可能的。我使用PostMan查尔斯代理来分析成功的HTTP,就像我在NodeJS文档中所做的那样。

对于POST来说,有几件事需要理解--两个二进制图像和一个文本字段( multipart/form-data ),它们仅依赖于核心NodeJS模块:

1)边界标识符

多部分/表单数据的边界是什么?

解决方案的第一部分是创建一个“边界标识符”,它是一个带有随机数的破折号-字符串。你可能想用什么就用什么,foorbar之类的。

代码语言:javascript
复制
------------0123456789

然后在每个数据块之间放置这个边界;无论是二进制数据还是仅仅文本数据。列出所有数据后,在末尾添加边界标识符,并附加两个破折号:

代码语言:javascript
复制
------------0123456789--

还需要将边界添加到headers中,以便接收post的服务器了解post数据的哪些行构成字段之间的边界。

代码语言:javascript
复制
const headers = {
    // Inform the server what the boundary identifier looks like
    'Content-Type': `multipart/form-data; boundary=${partBoundary}`,
    'Content-Length': binaryPostData.length
}

2)形式域元描述符

(这可能不是他们所称的)

您还需要一种方法来为您发送的每个表单字段编写元数据,无论该表单字段包含二进制还是文本对象。下面是图像文件的描述符,其中包含mime类型:

代码语言:javascript
复制
Content-Disposition: form-data; name="Image1"; filename="image-1.jpg"
Content-Type: image/jpeg

下面是文本字段的描述符:

代码语言:javascript
复制
Content-Disposition: form-data; name="comment"

邮政数据输出

所以发送到服务器的整个post数据如下所示:

代码语言:javascript
复制
----------------------------9110957588266537
Content-Disposition: form-data; name="Image1"; filename="image-1.jpg"
Content-Type: image/jpeg

ÿØÿàJFIFHHÿáLExifMMi
ÿí8Photoshop 3.08BIM8BIM%ÔÙ²é    ìøB~ÿÀ... <<<truncated for sanity>>>
----------------------------9110957588266537
Content-Disposition: form-data; name="Image2"; filename="image-2.jpg"
Content-Type: image/jpeg

ÿØÿàJFIFHHÿáLExifMMi
ÿí8Photoshop 3.08BIM8BIM%ÔÙ²é    ìøB~ÿÀ... <<<truncated for sanity>>>
----------------------------9110957588266537
Content-Disposition: form-data; name="comment"

This is a comment.
----------------------------9110957588266537--

一旦生成这些post数据,就可以将其转换为二进制数据,并将其写入HTTP请求:request.write(binaryPostData)

示例代码

下面是完整的示例代码,它允许您发布二进制文件和文本数据,而不必在代码中包含其他NodeJS库和包。

代码语言:javascript
复制
// This form data lists 2 binary image fields and text field
const form = [
    {
        name: 'Image1',
        type: 'file',
        value: 'image-1.jpg'
    },

    {
        name: 'Image2',
        type: 'file',
        value: 'image-2.jpg'
    },

    {
        name: 'comment',
        type: 'text',
        value: 'This is a comment.'
    }
]

// Types of binary files I may want to upload
const types = {
    '.json': 'application/json',
    '.jpg': 'image/jpeg'
}

const config = {
    host: 'ec2-192.168.0.1.compute-1.amazonaws.com',
    port: '80',
    path: '/api/route'
}

// Create an identifier to show where the boundary is between each
// part of the form-data in the POST
const makePartBoundary = () => {
    const randomNumbers = (Math.random() + '').split('.')[1]
    return '--------------------------' + randomNumbers
}

// Create meta for file part
const encodeFilePart = (boundary, type, name, filename) => {
    let returnPart = `--${boundary}\r\n`
    returnPart += `Content-Disposition: form-data; name="${name}"; filename="${filename}"\r\n`
    returnPart += `Content-Type: ${type}\r\n\r\n`
    return returnPart
}

// Create meta for field part
const encodeFieldPart = (boundary, name, value) => {
    let returnPart = `--${boundary}\r\n`
    returnPart += `Content-Disposition: form-data; name="${name}"\r\n\r\n`
    returnPart += value + '\r\n'
    return returnPart
}

const makePostData = {
    // Generate the post data for a file
    file: (item, partBoundary) => {
        let filePostData = ''

        // Generate the meta
        const filepath = path.join(__dirname, item.value)
        const extention = path.parse(filepath).ext
        const mimetype = types[extention]
        filePostData += encodeFilePart(partBoundary, mimetype, item.name, item.value)

        // Add the binary file data
        const fileData = fs.readFileSync(filepath, 'binary')
        filePostData += fileData
        filePostData += '\r\n'

        return filePostData
    },

    // Generate post data for the text field part of the form
    text: (item, partBoundary) => {
        let textPostData = ''
        textPostData += encodeFieldPart(partBoundary, item.name, item.value)
        return textPostData
    }
}

const post = () => new Promise((resolve, reject) => {
    let allPostData = ''

    // Create a boundary identifier (a random string w/ `--...` prefixed)
    const partBoundary = makePartBoundary()

    // Loop through form object generating post data according to type
    form.forEach(item => {
        if (Reflect.has(makePostData, item.type)) {
            const nextPostData = makePostData[item.type](item, partBoundary)
            allPostData += nextPostData
        }
    })

    // Create the `final-boundary` (the normal boundary + the `--`)
    allPostData += `--${partBoundary}--`

    // Convert the post data to binary (latin1)
    const binaryPostData = Buffer.from(allPostData, 'binary')

    // Generate the http request options
    const options = {
        host: config.host,
        port: config.port,
        path: config.path,
        method: 'POST',
        headers: {
            // Inform the server what the boundary identifier looks like
            'Content-Type': `multipart/form-data; boundary=${partBoundary}`,
            'Content-Length': binaryPostData.length
        }
    }

    // Initiate the HTTP request
    const req = http.request(options, res => {
        res.setEncoding('utf8')

        let body = ''

        // Accumulate the response data
        res.on('data', chunk => {
            body += chunk
        })

        // Resolve when done
        res.on('end', () => {
            resolve(body)
        })

        res.on('close', () => {
            resolve(body)
        })

        res.on('error', err => {
            reject(err)
        })
    })

    // Send the binary post data to the server
    req.write(binaryPostData)

    // Close the HTTP request object
    req.end()
})

// Post and log response
post().then(data => {
    console.log(data)
})
.catch(err => {
    console.error(err)
})
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44850661

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档