使用 Axios 在 Node JS 中复制 Python multipart/form-data Post

Replicate Python multipart/form-data Post in Node JS with Axios

我有这个 Python 代码可以成功地将文件发布到第三方 API。我正在尝试使用 Axios 在 Node 中重新创建此过程,但我 运行 遇到了一些问题。

def _publish_full_workbook(self, project_id:str, workbook_filename:str, workbook_file: str, workbook_bytes: bytes, file_extension: str) -> Element:
    # Builds the request
    url = self._get_site_url(f"workbooks?workbookType={file_extension}&overwrite=true")
    xml_request = Element('tsRequest')
    workbook_element = SubElement(xml_request, 'workbook', name=workbook_filename, showTabs='true')
    SubElement(workbook_element, 'project', id=project_id)

    # Finish building request for all-in-one method
    parts = {'request_payload': ('', tostring(xml_request), 'text/xml'),
             'tableau_workbook': (workbook_file, workbook_bytes, 'application/octet-stream')}
    payload, content_type = self._make_multipart(parts)
    headers = {'x-tableau-auth': self._auth_token, 'content-type': content_type}

    # Make the request to publish and check status code
    xml_response = self._post(url,xml_str=payload,headers=headers,success_code=201,pretty_print=True)
    return xml_response

@staticmethod
def _make_multipart(parts: dict) -> str:
    """
    Creates one "chunk" for a multi-part upload
    'parts' is a dictionary that provides key-value pairs of the format name: (filename, body, content_type).
    Returns the post body and the content type string.
    For more information, see this post:
        
    """
    mime_multipart_parts = []
    for name, (filename, blob, content_type) in parts.items():
        multipart_part = RequestField(name=name, data=blob, filename=filename)
        multipart_part.make_multipart(content_type=content_type)
        mime_multipart_parts.append(multipart_part)

    post_body, content_type = encode_multipart_formdata(mime_multipart_parts)
    content_type = content_type.replace("form-data","mixed")
    return post_body, content_type

我当前的代码如下所示:

publish = (project_id,workbook_path) => {
        return fsp.readFile(workbook_path).then(data => {
            const url = this.#site_url + "workbooks?workbookType=twbx&overwrite=true";
            var form = new FormData();
            const xml_payload = `<tsRequest><workbook name=\"restWorkbook\" ><project id=\"${project_id}\" ></project></workbook></tsRequest>`;
            const xml_payload_b64 = Buffer.from(xml_payload, 'binary').toString('base64')
            form.append("request_payload", xml_payload_b64, {
                contentType: 'text/xml'
            });
            form.append("tableau_workbook", data, {
                filename: path.basename(workbook_path),
                contentType: 'application/octet-stream'
            });
            const form_headers = form.getHeaders()
            form_headers['content-type'] = form_headers['content-type'].replace('form-data','mixed')
            const config = {
                headers: Object.assign({}, this.#auth_header, form_headers)
            };
            return axios.post(url, form, config);
        }).catch(error => {
            console.log("publishing failed")
            if('response' in error && 'status' in error['response']){
                console.log(error['response']['status'],error['response']['statusText'])
                console.log(error['response']['data'])
            }else{
                console.log(error)
            }
        })
    }

我从服务器收到一个错误:

  error: {
    summary: 'Bad Request',
    detail: 'Deserialization problem: Content is not allowed in prolog.; ',
    code: '400000'
  }

对我可能出错的地方有任何见解吗?

谢谢

这最终奏效了,只是做了一个小改动,这个:

        var form = new FormData();
        const xml_payload = `<tsRequest><workbook name=\"restWorkbook\" ><project id=\"${project_id}\" ></project></workbook></tsRequest>`;
        const xml_payload_b64 = Buffer.from(xml_payload, 'binary').toString('base64')
        form.append("request_payload", xml_payload_b64, {
            contentType: 'text/xml'
        });

必须是:

        var form = new FormData();
        const xml_payload = `<tsRequest><workbook name=\"restWorkbook\" ><project id=\"${project_id}\" ></project></workbook></tsRequest>`;
        form.append("request_payload", xml_payload, {
            contentType: 'text/xml'
        });