Facebook Graph API - загрузка фотографий с использованием JavaScript - PullRequest
40 голосов
/ 15 февраля 2011

Можно ли загрузить файл с помощью API Graph Facebook с использованием JavaScript, я чувствую, что я близок.Я использую следующий JavaScript

var params = {};
params['message'] = 'PicRolled';
params['source'] = '@'+path;
params['access_token'] = access_token;
params['upload file'] = true;

function saveImage() {
    FB.api('/me/photos', 'post', params, function(response) {
        if (!response || response.error) {
            alert(response);
        } else {
            alert('Published to stream - you might want to delete it now!');
        }
    }); 
}

При выполнении этого я получаю следующую ошибку ...

"OAuthException" - "(#324) Requires upload file"

Когда я пытаюсь исследовать этот метод, все, что я могу узнать,php метод, который должен решить эту проблемуЯ полагал, что это единственные, которые мне нужны для выполнения этой операции.

Я видел пару оставшихся без ответа вопросов по этому поводу в stackoverflow, надеюсь, я смогу объяснить себя достаточно.Спасибо, ребята.

Ответы [ 13 ]

44 голосов
/ 19 ноября 2011

Да, это возможно, я нахожу 2 решения, как это сделать, и они очень похожи друг другу, вам нужно просто определить параметр url для внешнего изображения url

ПЕРВЫЙ, использующий Javascript SDk:

var imgURL="http://farm4.staticflickr.com/3332/3451193407_b7f047f4b4_o.jpg";//change with your external photo url
FB.api('/album_id/photos', 'post', {
    message:'photo description',
    url:imgURL        
}, function(response){

    if (!response || response.error) {
        alert('Error occured');
    } else {
        alert('Post ID: ' + response.id);
    }

});

и ВТОРОЙ, используя jQuery Post и FormData:

 var postMSG="Your message";
 var url='https://graph.facebook.com/albumID/photos?access_token='+accessToken+"&message="+postMSG;
 var imgURL="http://farm4.staticflickr.com/3332/3451193407_b7f047f4b4_o.jpg";//change with your external photo url
 var formData = new FormData();
 formData.append("url",imgURL);

  $.ajax({
                    url: url,
                    data: formData,
                    cache: false,
                    contentType: false,
                    processData: false,
                    type: 'POST',

                    success: function(data){
                        alert("POST SUCCESSFUL");
                    }
                });
26 голосов
/ 15 февраля 2011

РЕДАКТИРОВАТЬ: этот ответ (в настоящее время) в значительной степени не имеет значения. Если ваше изображение находится в Интернете, просто укажите параметр url согласно API (см. Примеры в других ответах). Если вы хотите разместить изображение на Facebook напрямую, вы можете прочитать этот ответ, чтобы получить понимание. Также смотрите HTML5 Canvas.toDataUrl().

API говорит : "Чтобы опубликовать фотографию, отправьте запрос POST с вложением файла фотографии в виде multipart / form-data ."

FB ожидает, что байты загружаемого изображения находятся в теле HTTP-запроса, но их там нет. Или посмотреть на это по-другому - где в вызове FB.api () вы предоставляете фактическое содержимое самого изображения?

API FB.api () плохо документирован и не предоставляет пример HTTP POST, который включает тело. Из-за отсутствия такого примера можно сделать вывод, что это не поддерживается.

Это, вероятно, нормально - FB.api () использует что-то под названием XmlHttpRequest под обложками, которые поддерживает , включая тело ... посмотрите это в своем любимом справочнике по JavaScript.

Тем не менее, вам все еще нужно решить 2 подзадачи:

  1. как подготовить байты изображения (и остальную часть запроса) как multipart / form-data ; и
  2. получение байтов самого изображения

(кстати, необходимость кодировать тело сообщения, вероятно, то, для чего предназначен метод PHP setFileUploadSupport (true) - скажите объекту facebook, чтобы кодировал тело сообщения как multipart/form-data перед отправкой)

Но это немного мизернее, чем это

К сожалению, подзадача '2' может укусить вас - нет способа (в прошлый раз, когда я смотрел) извлечь байты изображения из предоставленного браузером объекта Image.

Если загружаемое изображение доступно через URL, вы можете получить байты с помощью XmlHttpRequest. Не так уж плохо.

Если изображение поступает с рабочего стола пользователя, вы можете предложить пользователю:

 <form enctype="multipart/form-data">
     <input type="filename" name="myfile.jpg" />
     <input type="hidden" name="source" value="@myfile.jpg"/>
     <input type="hidden" name="message" value="My Message"/>
     <input type="hidden" name="access_token" value="..."/> 
 </form> 

(обратите внимание, что source ссылается на имя, данное виджету загрузки файлов)

... и надеемся, что FB ожидает получения данных таким образом (сначала попробуйте использовать статическую HTML-форму, прежде чем динамически кодировать ее в JS). Можно сделать вывод, что на самом деле это так, поскольку они не предлагают другого способа сделать это.

17 голосов
/ 20 ноября 2011

Я использовал код @ Владимир Дворник с некоторыми изменениями, у меня была та же проблема, и с этим кодом она работала очень хорошо:

        var imgURL = //your external photo url
        FB.api('/photos', 'post', {
            message: 'photo description',
            access_token: your accesstoken 
            url: imgURL
        }, function (response) {

            if (!response || response.error) {
                alert('Error occured:' + response);
            } else {
                alert('Post ID: ' + response.id);
            }

        });
11 голосов
/ 30 марта 2012

Фотографии можно загружать в профиль Facebook с помощью Ajax следующим образом.

$.ajax({
            type: "POST",
            url: "https://graph.facebook.com/me/photos",
            data: {
                message: "Your Msg Goes Here",
                url: "http://www.knoje.com/images/photo.jpg[Replace with yours]",
                access_token: token,
                format: "json"
            },
            success: function(data){
               alert("POST SUCCESSFUL"); }
            });

Так что это лучший способ опубликовать фотографию в профиле Facebook с помощью GRAPH API, и это простойone.

Во многих ответах я видел, что URL-адрес изображения показан источником, изображением или изображением и т. д., но это не работает.

Использование источника, изображения или изображения приводит к (# 324) Требуется загрузить файл ошибка.

Лучший способ избежать ошибки 324.

6 голосов
/ 10 мая 2015

Только ответ @ Thiago отвечает на вопрос загрузки данных через javascript. Я обнаружил, что API JS Facebook не охватывает эту ситуацию.

Я также заварил и проверил свое личное решение.

Основные шаги

  1. Получить двоичные данные изображения (я использовал холст, но использование поля ввода также возможно)
  2. Формирует составной запрос со всеми необходимыми данными для вызова API графа
  3. Включить двоичные данные в запрос
  4. Закодировать все в двоичном массиве и отправить его через XHR

Код

Конверсионные утилиты

var conversions = {
  stringToBinaryArray: function(string) {
    return Array.prototype.map.call(string, function(c) {
      return c.charCodeAt(0) & 0xff;
    });
  },
  base64ToString: function(b64String) {
    return atob(b64String);
  }
};

Фрагмент публикации изображения

var DEFAULT_CALL_OPTS = {
  url: 'https://graph.facebook.com/me/photos',
  type: 'POST',
  cache: false,
  success: function(response) {
    console.log(response);
  },
  error: function() {
    console.error(arguments);
  },
  // we compose the data manually, thus
  processData: false,
  /**
   *  Override the default send method to send the data in binary form
   */
  xhr: function() {
    var xhr = $.ajaxSettings.xhr();
    xhr.send = function(string) {
      var bytes = conversions.stringToBinaryArray(string);
      XMLHttpRequest.prototype.send.call(this, new Uint8Array(bytes).buffer);
    };
    return xhr;
  }
};
/**
 * It composes the multipart POST data, according to HTTP standards
 */
var composeMultipartData = function(fields, boundary) {
  var data = '';
  $.each(fields, function(key, value) {
    data += '--' + boundary + '\r\n';

    if (value.dataString) { // file upload
      data += 'Content-Disposition: form-data; name=\'' + key + '\'; ' +
        'filename=\'' + value.name + '\'\r\n';
      data += 'Content-Type: ' + value.type + '\r\n\r\n';
      data += value.dataString + '\r\n';
    } else {
      data += 'Content-Disposition: form-data; name=\'' + key + '\';' +
        '\r\n\r\n';
      data += value + '\r\n';
    }
  });
  data += '--' + boundary + '--';
  return data;
};

/**
 * It sets the multipart form data & contentType
 */
var setupData = function(callObj, opts) {
  // custom separator for the data
  var boundary = 'Awesome field separator ' + Math.random();

  // set the data
  callObj.data = composeMultipartData(opts.fb, boundary);

  // .. and content type
  callObj.contentType = 'multipart/form-data; boundary=' + boundary;
};

// the "public" method to be used
var postImage = function(opts) {

  // create the callObject by combining the defaults with the received ones
  var callObj = $.extend({}, DEFAULT_CALL_OPTS, opts.call);

  // append the access token to the url
  callObj.url += '?access_token=' + opts.fb.accessToken;

  // set the data to be sent in the post (callObj.data = *Magic*)
  setupData(callObj, opts);

  // POST the whole thing to the defined FB url
  $.ajax(callObj);
};

Использование

postImage({
  fb: { // data to be sent to FB
    caption: caption,
    /* place any other API params you wish to send. Ex: place / tags etc.*/
    accessToken: 'ACCESS_TOKEN',
    file: {
      name: 'your-file-name.jpg',
      type: 'image/jpeg', // or png
      dataString: image // the string containing the binary data
    }
  },
  call: { // options of the $.ajax call
    url: 'https://graph.facebook.com/me/photos', // or replace *me* with albumid
    success: successCallbackFunction,
    error: errorCallbackFunction
  }
});

Extra

Извлечение двоичного строкового представления изображения холста

var getImageToBeSentToFacebook = function() {
  // get the reference to the canvas
  var canvas = $('.some-canvas')[0];

  // extract its contents as a jpeg image
  var data = canvas.toDataURL('image/jpeg');

  // strip the base64 "header"
  data = data.replace(/^data:image\/(png|jpe?g);base64,/, '');

  // convert the base64 string to string containing the binary data
  return conversions.base64ToString(data);
}

Информация о том, как загрузить двоичную строку из input[type=file]

HTML5 File API, читаемый как текстовый и бинарный

Примечания:

  1. Конечно, есть и альтернативные подходы.
    • Использование HTML-формы в iframe - вы не можете получить ответ на звонок
    • Использование подхода FormData & File, но, к сожалению, в этом случае есть много несовместимостей, которые затрудняют использование процесса, и вы в конечном итоге обвязка несоответствий - поэтому я выбрал ручную сборку данных, поскольку стандарты HTTP редко меняются:)
  2. Решение не требует специальных функций HTML5.
  3. В приведенном выше примере используются jQuery.ajax, jQuery.extend, jQuery.each
4 голосов
/ 12 июля 2012

Да, вы можете сделать эту публикацию данных в iframe, например здесь , или вы можете использовать jQuery File Upload .Проблема в том, что вы не можете получить ответ от iframe, используя плагин, вы можете использовать дескриптор страницы.

Пример: загрузить видео с помощью jQuery File Upload

<form id="fileupload" action="https://graph-video.facebook.com/me/photos" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="acess_token" value="user_acess_token">
    <input type="text" name="title">
    <input type="text" name="description">
    <input type="file" name="file"> <!-- name must be file -->
</form>


<script type="text/javascript">

    $('#fileupload').fileupload({
        dataType: 'json',
        forceIframeTransport: true, //force use iframe or will no work
        autoUpload : true,
        //facebook book response will be send as param
        //you can use this page to save video (Graph Api) object on database
        redirect : 'http://pathToYourServer?%s' 
    });
</script>
2 голосов
/ 20 октября 2014

Это работает:

   function x(authToken, filename, mimeType, imageData, message) {
    // this is the multipart/form-data boundary we'll use
    var boundary = '----ThisIsTheBoundary1234567890';

    // let's encode our image file, which is contained in the var
    var formData = '--' + boundary + '\r\n';
    formData += 'Content-Disposition: form-data; name="source"; filename="' + filename + '"\r\n';
    formData += 'Content-Type: ' + mimeType + '\r\n\r\n';
    for (var i = 0; i < imageData.length; ++i) {
        formData += String.fromCharCode(imageData[i] & 0xff);
    }
    formData += '\r\n';
    formData += '--' + boundary + '\r\n';
    formData += 'Content-Disposition: form-data; name="message"\r\n\r\n';
    formData += message + '\r\n';
    formData += '--' + boundary + '--\r\n';

    var xhr = new XMLHttpRequest();
    xhr.open('POST', 'https://graph.facebook.com/me/photos?access_token=' + authToken, true);
    xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);

    // Solving problem with sendAsBinary for chrome
    try {
        if (typeof XMLHttpRequest.prototype.sendAsBinary == 'undefined') {
            XMLHttpRequest.prototype.sendAsBinary = function(text) {
                var data = new ArrayBuffer(text.length);
                var ui8a = new Uint8Array(data, 0);
                for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
                this.send(ui8a);
            }
        }
    } catch (e) {}
    xhr.sendAsBinary(formData);
};
2 голосов
/ 01 сентября 2014

Это все еще работает.Я использую его, как показано ниже:

var formdata= new FormData();
if (postAs === 'page'){
    postTo = pageId; //post to page using pageID
}

formdata.append("access_token", accessToken); //append page access token if to post as page, uAuth|paAuth
formdata.append("message", photoDescription);
formdata.append("url", 'http://images/image.png');

try {
    $.ajax({
        url: 'https://graph.facebook.com/'+ postTo +'/photos',
        type: "POST",
        data: formdata,
        processData: false,
        contentType: false,
        cache: false,
        error: function (shr, status, data) {
            console.log("error " + data + " Status " + shr.status);
        },
        complete: function () {
            console.log("Successfully uploaded photo to Facebook");
        }
    });
} catch (e) {
    console.log(e);
}

Я должен спросить, есть ли у вас люди идеи, если это целесообразно или имеет большой риск безопасности по сравнению с использованием PHP API для Facebook.

2 голосов
/ 23 ноября 2013

https://stackoverflow.com/a/16439233/68210 содержит решение, которое работает, если вам нужно загрузить сами данные фотографии и у вас нет URL.

2 голосов
/ 06 ноября 2012

Чтобы загрузить файл с локального компьютера только с помощью Javascript, попробуйте HelloJS

<form onsubmit="upload();">
     <input type="file" name="file"/>
     <button type="submit">Submit</button>
</form>

<script>
function upload(){
   hello.api("facebook:/me/photos", 'post', document.getElementById('form'), function(r){
      alert(r&&!r.error?'Success':'Failed'); 
   });
}
</script>

Демонстрация загрузки http://adodson.com/hello.js/demos/upload.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...