Error multipart boundary not found

I don't know why I receive on server [Error: Multipart: Boundary not found] and bundle.js:37628 POST http://localhost:8800/exporttocsv 500 (Internal Server Error) When I make post through <f...

I was getting this problem with Axios via JavaScript because the content-type header was multipart-form-data but the boundary was missing.

Based on my research, a good way to handle it is to allow Axios to auto-detect the content type and set the headers correctly itself.

Here is an idea for how to accomplish this:

const formDataWithFiles = hasFiles ? new FormData() : undefined;

if (formDataWithFiles) {
    // axios will automatically set the content-type to multipart/form-data if the
    // data param is a FormData object
    // otherwise, it will use application/json
    // (study the Dev Tools > Network tab > XHR tab headers)
    Object.keys(modifiedFields)
        .forEach(field => formDataWithFiles.append(field, modifiedFields[field]));
}

const { data } = await axios({
    method,
    url: actionUrl,
    data: hasFiles ? formDataWithFiles : modifiedFields,
    headers: {
        ...axios.defaults.headers,
        ...headers,
    },
});

return data;

The above code is in a generic handleSubmit function that can be called from anywhere in the client-side.

Here is the function signature:

const { data } = await this.submitForm({
    actionUrl: this.actionUrl,
    method: this.method,
    modifiedFields: {
        ...this.modifiedUser,
    },
    hasFiles: true,
});

In the above code, there are two use cases. The first is the default case, where a normal payload is sent via a flat object. The second is the case when the form has files and you want multipart/form-data. In this case, we use the FormData Object as a vessel to instruct Axios to auto-detect the necessary headers and set the correct boundary.

If you do not specify the headers correctly, it is possible to receive an empty $request->all() Array in Laravel, or perhaps any server such as node.js.

The short answer to my answer is to use the FormData Object because it contains more information than a plain-old-JavaScript-object. With it, you can also access:

const formData = new FormData();

console.log('boundary:', formData._boundary);

As my annotation above hints towards, use the Dev Tools > Network tab > XHR tab to examine your request headers and make sure you have content-type application/json or application/x-www-form-urlencoded for regular form submits and multipart/form-data' if you are uploading a file.

«dependencies»: {
«@nestjs/common»: «^7.0.9»,
«@nestjs/core»: «^7.0.9»,
«@nestjs/jwt»: «^7.0.0»,
«@nestjs/passport»: «^7.0.0»,
«@nestjs/platform-express»: «^7.0.9»,
«@nestjs/schedule»: «^0.3.1»,
«@nestjs/typeorm»: «^7.0.0»,
«@sentry/node»: «^5.15.5»,
«aws-sdk»: «^2.674.0»,
«axios»: «^0.19.2»,
«bcryptjs»: «^2.4.3»,
«body-parser»: «^1.19.0»,
«class-transformer»: «^0.2.3»,
«class-validator»: «^0.12.2»,
«dotenv-safe»: «^8.2.0»,
«express-rate-limit»: «^5.1.3»,
«faker»: «^4.1.0»,
«handlebars»: «^4.7.6»,
«ioredis»: «^4.16.3»,
«module-alias»: «^2.2.2»,
«ms»: «^2.1.2»,
«nestjs-s3»: «^1.0.1»,
«nodemailer»: «^6.4.6»,
«passport»: «^0.4.1»,
«passport-jwt»: «^4.0.0»,
«pg»: «^8.1.0»,
«pino»: «^6.2.1»,
«rate-limit-redis»: «^1.7.0»,
«reflect-metadata»: «^0.1.13»,
«rxjs»: «^6.5.5»,
«source-map-support»: «^0.5.19»,
«typeorm»: «^0.2.24»,
«uuid»: «^8.0.0»
},
«devDependencies»: {
«@nestjs/cli»: «^7.1.5»,
«@nestjs/schematics»: «^7.0.0»,
«@types/bcryptjs»: «^2.4.2»,
«@types/body-parser»: «^1.19.0»,
«@types/dotenv-safe»: «^8.1.0»,
«@types/express»: «^4.17.6»,
«@types/express-rate-limit»: «^5.0.0»,
«@types/faker»: «^4.1.11»,
«@types/ioredis»: «^4.16.1»,
«@types/module-alias»: «^2.0.0»,
«@types/ms»: «^0.7.31»,
«@types/node»: «^12.12.38»,
«@types/nodemailer»: «^6.4.0»,
«@types/passport-jwt»: «^3.0.3»,
«@types/pino»: «^6.0.1»,
«@types/rate-limit-redis»: «^1.7.1»,
«@types/source-map-support»: «^0.5.1»,
«@types/uuid»: «^7.0.3»,
«newman»: «^5.0.0»,
«pino-pretty»: «^4.0.0»,
«pm2»: «^4.4.0»,
«prettier»: «^2.0.5»,
«ts-loader»: «^7.0.4»,
«ts-node»: «^8.10.1»,
«tsconfig-paths»: «^3.9.0»,
«tslint»: «^6.1.2»,
«tslint-config-prettier»: «^1.18.0»,
«tslint-config-standard»: «^9.0.0»,
«tslint-sonarts»: «^1.9.0»,
«typeorm-seeding»: «^1.6.1»,
«typescript»: «^3.8.3»
},
«optionalDependencies»: {
«husky»: «^4.2.1»,
«lint-staged»: «^10.0.7»
}

При отправке изображения получаю ошибку Error: Multipart: Boundary not found
На фронтенде отправка выглядит следующим образом
1. View

<input type="file" id="file" (change)="handleFileInput($event.target.files)">

2. Component

handleFileInput(files: FileList) {
        this.fileToUpload = files.item(0);
        this.userService.postFile(this.fileToUpload)
            .subscribe(
                response => {
                    console.log(response);
                },
                error => {
                    console.log('error', error);
                }
            );
    }

3. Service

postFile(fileToUpload: File): Observable<any> {
        const formData: FormData = new FormData();
        formData.append('fileKey', fileToUpload, fileToUpload.name);
        return this.apiService.post(this.apiConfig.photo, formData, true);
    }

Вот что я вижу во вкладке Network
General

Request URL: http://localhost:8000/api/photo
Request Method: POST
Status Code: 500 Internal Server Error
Remote Address: [::1]:8000
Referrer Policy: no-referrer-when-downgrade
<b>Response Headers</b>
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
Access-Control-Allow-Methods: GET,PUT,POST,PATCH,DELETE
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 1864
Content-Security-Policy: default-src 'self'
Content-Type: text/html; charset=utf-8
Date: Mon, 07 May 2018 12:56:18 GMT
X-Content-Type-Options: nosniff
X-Powered-By: Express

Request Headers

Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Authorization: xxx
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 2
Content-Type: multipart/form-data
Host: localhost:8000
Origin: http://localhost:4200
Pragma: no-cache
Referer: http://localhost:4200/user/test

Request payload

{}
No properties

На бекенде NodeJS использую multer

const multer = require("multer");

var eventStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "./storage");
  },
  filename: function (req, file, cb) {
    var filename = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    for (var i = 0; i < 20; i++) {
      filename += possible.charAt(Math.floor(Math.random() * possible.length));
    }
    cb(null, filename + '.' + mime.extension(file.mimetype));
  }
});
var uploadEvent = multer({
  storage: eventStorage
});
router.post('/api/photo', auth.ensureAuthenticated, uploadEvent.any() , function (request, response) {
  console.log(request.files);
  handler.success(response, '', request.files);
});

Я не могу понять, где косяк — на фронтенде или бекенде?
Смущает пустой объект в Request payload, по идее там должен быть файл в виде хеша или типа того?

Today, when the front-end uses Vue to transfer files with formdata, the background node reports an error

Multipart: Boundary not found multer

It is found in the front console that the file file transmitted by the interface is null {}, because it is set when Axios requests

the Header of Content-Type is multipart/form-data

It is found that there is no boundary parameter later, except multipart/form data

multipart/form-data;boundary :****************

There should also be a series of boundary parameters. First of all, do not splice the contents behind the boundary, otherwise you need to reconfigure all the content parameters yourself.
later, it is found that it is the reason for the request method, and you need to use ajax to make the request.
the solution is as follows

// upload the files
export function reqUploadImg(file, user_id) {
  return axios({
    url: '/uploadImg',
    method: 'POST',
    Headers: {
      "content-type": "multipart/form-data",
    },
    data: file,
    params: { user_id }
  })
}

This problem can be solved. It will automatically splice a string later, or “content type”: “multipart/form-data” in “multipart/form-data” will also be spliced automatically if it is set to fasle, but after personal experiments, it is found that the types have changed into JSON format, which is automatically generated by Axios source code

Read More:

Передняя часть использует запрос на размещение axios для загрузки файлов, а сервер Node сообщает об ошибке.Error: Multipart: Boundary not found.

server is running .  http://:::3000
Error: Multipart: Boundary not found
    at new Multipart (/home/w/my/project-exercise/FileServer/node_modules/busboy/lib/types/multipart.js:58:11)
    at Multipart (/home/w/my/project-exercise/FileServer/node_modules/busboy/lib/types/multipart.js:26:12)
    at Busboy.parseHeaders (/home/w/my/project-exercise/FileServer/node_modules/busboy/lib/main.js:71:22)
    at new Busboy (/home/w/my/project-exercise/FileServer/node_modules/busboy/lib/main.js:22:10)
    at multerMiddleware (/home/w/my/project-exercise/FileServer/node_modules/multer/lib/make-middleware.js:33:16)
    at Layer.handle [as handle_request] (/home/w/my/project-exercise/FileServer/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/w/my/project-exercise/FileServer/node_modules/express/lib/router/index.js:317:13)
    at /home/w/my/project-exercise/FileServer/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/w/my/project-exercise/FileServer/node_modules/express/lib/router/index.js:335:12)
    at next (/home/w/my/project-exercise/FileServer/node_modules/express/lib/router/index.js:275:10)

Сервер Node использует другие методы для загрузки теста и прохождения, внешний код загрузки vue выглядит следующим образом

      let file = document.getElementById('file').files[0]
      console.log(file)
      this.axios.put('http://192.168.xxx.xxx:3000/file_upload_put', file, {
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        transformRequest: [function (data) {
          return data
        }],
        onUploadProgress: progressEvent => {
          let complete = (progressEvent.loaded / progressEvent.total * 100 | 0) + '%'
          console.log('complete: ', complete)
        }
      })
      .then((response) => {
        if (response.status === 200) {
          console.log('success upload')
        }
      })

Решение

Не доставленformData Объект заставил сервер сообщить об ошибке, и запрос на размещение включилfile Объект добавлен вformData , Пройти напрямуюformData Объект можно загрузить в обычном режиме

      let file = document.getElementById('file').files[0]
      console.log(file)
      let formData = new FormData()
      formData.append('image', file)
      this.axios.put('http://192.168.xxx.xxx:3000/file_upload_put', formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        transformRequest: [function (data) {
          return data
        }],
        onUploadProgress: progressEvent => {
          let complete = (progressEvent.loaded / progressEvent.total * 100 | 0) + '%'
          console.log('complete: ', complete)
        }
      })
      .then((response) => {
        if (response.status === 200) {
          console.log('success upload')
        }
      })

I was getting this problem with Axios via JavaScript because the content-type header was multipart-form-data but the boundary was missing.

Based on my research, a good way to handle it is to allow Axios to auto-detect the content type and set the headers correctly itself.

Here is an idea for how to accomplish this:

const formDataWithFiles = hasFiles ? new FormData() : undefined;

if (formDataWithFiles) {
    // axios will automatically set the content-type to multipart/form-data if the
    // data param is a FormData object
    // otherwise, it will use application/json
    // (study the Dev Tools > Network tab > XHR tab headers)
    Object.keys(modifiedFields)
        .forEach(field => formDataWithFiles.append(field, modifiedFields[field]));
}

const { data } = await axios({
    method,
    url: actionUrl,
    data: hasFiles ? formDataWithFiles : modifiedFields,
    headers: {
        ...axios.defaults.headers,
        ...headers,
    },
});

return data;

The above code is in a generic handleSubmit function that can be called from anywhere in the client-side.

Here is the function signature:

const { data } = await this.submitForm({
    actionUrl: this.actionUrl,
    method: this.method,
    modifiedFields: {
        ...this.modifiedUser,
    },
    hasFiles: true,
});

In the above code, there are two use cases. The first is the default case, where a normal payload is sent via a flat object. The second is the case when the form has files and you want multipart/form-data. In this case, we use the FormData Object as a vessel to instruct Axios to auto-detect the necessary headers and set the correct boundary.

If you do not specify the headers correctly, it is possible to receive an empty $request->all() Array in Laravel, or perhaps any server such as node.js.

The short answer to my answer is to use the FormData Object because it contains more information than a plain-old-JavaScript-object. With it, you can also access:

const formData = new FormData();

console.log('boundary:', formData._boundary);

As my annotation above hints towards, use the Dev Tools > Network tab > XHR tab to examine your request headers and make sure you have content-type application/json or application/x-www-form-urlencoded for regular form submits and multipart/form-data' if you are uploading a file.

By default axios do not attach boundary to content type header. You have to do it manually:

axios.post(`${this.baseUrl}/${path}`, formData, {
      headers: {
        'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`,
      },
    })

It is especially important if you talking to spring server.

In other case you will see exception:

org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found

I was struggling with this issue of multipart boundary not found with fetch api calling to a nestjs server. What I tried was to remove the

'Content-Type': 'multipart/form-data',

headers so that Fetch api automatically set the headers and it worked. Try it out

You can do this …

Instantiate a new FormData instance.

const config = { headers: { 'Content-Type': 'multipart/form-data' } };
let fd = new FormData();
fd.append('file',files[0])
return axios.post("http://localhost:5000/upload", fd, config)

Usingconcat and concat-stream

const concat = require("concat-stream")
const fd = new FormData()

fd.append("hello", "world")
fd.append("file", fs.createReadStream(file))
fd.pipe(concat(data => {
  axios.post("/hello", data, {
    headers: fd.getHeaders()
  })
}))

Using promise

const promise = new Promise((resolve) => {
  const fd = new FormData();
  fd.append("hello", "world");
  fd.append("file", fs.createReadStream(binaryFile));
  fd.pipe(concat({ encoding: 'buffer' }, data => resolve({ data, headers: fd.getHeaders() })));
});
promise.then(({ data, headers }) => axios.post('/hello', data, { headers }));

I hope I’ve been useful! :)

References:

  • github.com — Can’t get a .post with Content-Type…
  • github.com — Better solution using axios, form-data, fs
  • https://stackoverflow.com/a/47630754/3332734

Понравилась статья? Поделить с друзьями:
  • Error multidimensional array must have bounds for all dimensions except the first
  • Error mugen character
  • Error msg установка драйвера ошибка установки msg error monetreport
  • Error msg unable to process command password is set but no password file is provided
  • Error msg bcu return value real 10 translated 10