javascript - http form ajax




Safari 11.1:입력[type=file]이 비어 있으면 ajax/XHR 양식 제출이 실패합니다. (4)

Perl 프로그램에서 같은 문제가있는 것으로 보았습니다.

Perl에서 multipart / form-data를 처리하면 양식 파일 요소가 비어있을 때 Apple 장치에서 Apache 오류가 발생합니다

해결 방법은 양식 데이터가 할당되기 전에 양식 요소를 제거하는 것입니다.

$('#myForm').find("input[type='file']").each(function(){
    if ($(this).get(0).files.length === 0) {$(this).remove();}
});
var fData = new FormData($('#myForm')[0]);
...

업데이트 : Webkit 빌드 r230963 현재이 문제는 Webkit에서 해결되었습니다.

===========

Safari Technology Preview 11.2뿐만 아니라 MacOS 및 iOS의 최근 Safari 11.1 업데이트 이후로 input[type=file] 필드에 파일이 선택되어 있지 않으면 웹 응용 프로그램의 $.ajax 호출이 실패합니다 (필요하지 않음). 내 양식). 필드에 파일이 선택 되어도 실패 하지 않습니다 .

ajaxerror 콜백이 실행되고 Safari 콘솔에 다음 메시지가 표시됩니다. Failed to load resource: The operation couldn't be completed. Protocol error Failed to load resource: The operation couldn't be completed. Protocol error 입니다. 나는 HTTPS이며 동일한 도메인 (및 서버)의 위치에 HTTPS를 통해 제출합니다.

11.1 업데이트가 있기 전에 파일을 선택하지 않았을 때 $.ajax 호출이 정상적으로 전송되었습니다. Chrome과 Firefox의 최신 버전에는 문제가 없습니다.

내 코드의 관련 부분 :

입력 :

Browse... <input id="file-upload" type="file" name="image" accept=".jpg,.jpeg">

JS :

var formData = new FormData($(this)[0]);
$.ajax({
    type: 'POST',
    enctype: 'multipart/form-data',
    url: '../process.php',
    data: formData,
    contentType: false,
    processData: false,
    cache: false,
    success: function(response) { ... },
    error: function() { //my code reaches here }
});

임시 (잘하면) 해결책으로, 빈 파일 필드를 감지하고 formData 에서 ajax 호출 전에 제거하고 모든 것이 예상대로 / 이전에 작동합니다.

$("input[type=file]").each(function() {
    if($(this).val() === "") {
        formData.delete($(this).attr("name"));
    }
});

내가 잘못했거나 Safari에 문제가 있습니까? 아니면 Safari에서 변경 되었습니까? 이제는 ajax 호출에서 설명해야합니다.


이 문제를 해결하기 위해 jQuery remove () 메서드를 사용하여 DOM에서 입력 유형 파일을 완전히 삭제합니다.

$("input[type=file]").each(function() {
    if($(this).val() === "") {
        $(this).remove();
    }
});

업데이트 : 이전 답변은 Firefox에서 작동하지 않습니다.

Firefox는 빈 파일 필드의 FormData.get()빈 문자열 을 반환합니다 (다른 브라우저의 File 객체 대신). 따라서 오래된 해결 방법을 사용할 때 빈 <input type="file"> 이 빈 <input type="text"> 처럼 전송됩니다. 아쉽게도 FormData 객체를 만든 후 빈 텍스트와 빈 텍스트를 구별 할 수있는 방법이 없습니다.

이 솔루션을 대신 사용하십시오.

var $form = $('form')
var $inputs = $('input[type="file"]:not([disabled])', $form)
$inputs.each(function(_, input) {
  if (input.files.length > 0) return
  $(input).prop('disabled', true)
})
var formData = new FormData($form[0])
$inputs.prop('disabled', false)

라이브 데모 : https://jsfiddle.net/ypresto/05Lc45eL/

비 jQuery 환경의 경우 :

var form = document.querySelector('form')
var inputs = form.querySelectorAll('input[type="file"]:not([disabled])')
inputs.forEach(function(input) {
  if (input.files.length > 0) return
  input.setAttribute('disabled', '')
})
var formData = new FormData(form)
inputs.forEach(function(input) {
  input.removeAttribute('disabled')
})

Rails (rails-ujs / jQuery-ujs) : https://gist.github.com/ypresto/cabce63b1f4ab57247e1f836668a00a5

이전 답변 :

FormData 필터링 (Ravichandra Adiga의 답변에서)은 DOM을 조작하지 않기 때문에 더 좋습니다.

그러나 FormData의 파트 순서는 <form> 사양에 따라 폼의 요소를 입력하는 순서와 동일해야합니다 . 다른 사람이이 사양에 의존하면 다른 버그가 발생할 수 있습니다.

아래 스 니펫은 FormData 순서와 빈 부분을 유지합니다.

var formDataFilter = function(formData) {
    // Replace empty File with empty Blob.
  if (!(formData instanceof window.FormData)) return
  if (!formData.keys) return // unsupported browser
  var newFormData = new window.FormData()
  Array.from(formData.entries()).forEach(function(entry) {
    var value = entry[1]
    if (value instanceof window.File && value.name === '' && value.size === 0) {
      newFormData.append(entry[0], new window.Blob(), '')
    } else {
      newFormData.append(entry[0], value)
    }
  })
  return newFormData
}

실례는 여기에 있습니다 : https://jsfiddle.net/ypresto/y6v333bq/

Rails의 경우 다음을 참조하십시오. https://github.com/rails/rails/issues/32440#issuecomment-381185380

(참고 : iOS 11.3의 Safari에는이 문제가 있지만 11.2는 그렇지 않습니다.)


    var fileNames = formData.getAll("filename[]");
    formData.delete("filename[]");
    jQuery.each(fileNames, function (key, fileNameObject) {
        if (fileNameObject.name) {
            formData.append("filename[]", fileNameObject);
        }
    });

이 시도 !!





safari