【问题标题】:Facebook Graph API - upload photo using JavaScriptFacebook Graph API - 使用 JavaScript 上传照片
【发布时间】:2011-06-27 07:23:50
【问题描述】:

是否可以使用 javascript 使用 Facebook Graph API 上传文件,我觉得我很接近。我正在使用以下 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 方法

$facebook->setFileUploadSupport(true);

但是,我使用的是 JavaScript,看起来这种方法可能与 Facebook Graph 权限有关,但我已经设置了权限 user_photos 和 publish_stream,我认为这是我执行此操作所需的唯一权限。

我在 stackoverflow 上看到了一些关于此的未回答的问题,希望我能充分解释自己。谢谢大家。

【问题讨论】:

  • 如果您在这里寻找答案,请超越第一个答案

标签: javascript facebook facebook-graph-api file-upload


【解决方案1】:

是的,这是可能的,我找到了 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");
                    }
                });

【讨论】:

  • 我使用了第二个,它给了我:“$ is not defined”
  • ofcource,你需要添加jquery库;)
  • 第一个完美运行,我不知道为什么文档甚至没有指定 url 参数。
  • 这个方法失效了吗?我已经使用第一种方法几个月了,然后突然失败(发送无效的图像消息)并尝试使用第二种方法并给我同样的错误消息。
  • @Oso 我收到 500 条消息已经有一段时间了,现在似乎还可以。 Владимир Дворник,非常感谢您引用 url 参数,api doc 确实很烂。
【解决方案2】:

编辑:这个答案(现在)在很大程度上无关紧要。如果您的图像在网络上,只需按照API 指定url 参数(并参见其他答案中的示例)。如果您想将图像内容直接发布到 facebook,您可能需要阅读此答案以获得理解。另请参阅 HTML5 的 Canvas.toDataUrl()

API says:“要发布照片,请发出 POST 请求照片文件附件为 multipart/form-data。”

FB 预计要上传的图像字节在 HTTP 请求的正文中,但它们不存在。或者以另一种方式看待它 - 您在 FB.api() 调用中的哪个位置提供图像本身的实际内容?

FB.api() 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 中动态编码)。人们可能会推断实际上它会,因为他们没有提供另一种方法。

【讨论】:

  • 谢谢,也许我应该使用 php 似乎更直接,但我会先试试这个!
  • bullock 可以从 url 访问路径,所以您认为提供图像数据而不是路径会是一个 xml http 请求,并且我的其余代码看起来还可以吗?今晚晚些时候我才能尝试,但再次感谢
  • 最终,要使用此 API,您需要获取图像的字节,然后将包含这些字节的请求编码为 multipart/form-data,然后将其作为 POST 请求的主体发送到facebook 服务器。
  • 如果您有闲暇时间让服务器上传图像,那么我可能无论如何都会这样做。在各种浏览器中使用 XmlHttpRequest 对象的非标准二进制功能,您就不会那么头疼了,而且您不会因为同源策略而大吃一惊。无论如何,服务器可能比浏览器“连接得更好”,并且会更快地完成工作。
  • 嗨,David,如果字节来自 canvas.toDataURL()(假设我们解码 base64),那么在 HTTP POST 请求的正文中上传会起作用吗?
【解决方案3】:

我使用@Владимир Дворник 代码进行了一些修改,我遇到了同样的问题,并且这段代码运行良好:

        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);
            }

        });

【讨论】:

  • 这行得通,尽管我对url 有点警惕,因为它似乎没有记录在案。但是那么少。
  • 今天这对我有用。不知道这种情况会持续多久。可能与任何记录在案的功能一样可靠。 :)
  • 如何获取accesstoken?
  • access_token 来自 FB.login() 响应
  • 为什么会自动创建相册
【解决方案4】:

可以使用 Ajax 将照片上传到 Facebook 个人资料,如下所示。

$.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"); }
            });

因此,这是使用 GRAPH API 将照片发布到 facebook 个人资料的最佳方式,而且非常简单。

在许多答案中,我已经看到图像 url 由源、图片或图像等显示,但这不起作用。

使用源、图片或图像导致(#324) 需要上传文件错误。

避免 324 错误的最佳方法。

【讨论】:

  • 如果要上传本地图片怎么办? (即,图像在您的手机/计算机中,而不是在其他地方托管)
  • 根据 fb api,您必须指定要发布的图像的 url,您可以尝试提供图像的本地路径以防万一。
【解决方案5】:

只有@Thiago 的答案是通过javascript 回答上传 数据的问题。我发现 Facebook JS API 没有涵盖这种情况。

我还酿造并测试了我的个人解决方案。

主要步骤

  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);
  }
};

图片发布sn-p

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
  }
});

额外

提取画布图像的二进制字符串表示

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 read as text and binary

注意事项:

  1. 当然还有其他方法
    • 在 iframe 中使用 HTML 表单 - 您无法从调用中获得响应
    • 使用FormDataFile 方法,但不幸的是,在这种情况下,存在许多不兼容的问题,这使得该过程更难使用,并且您最终会围绕不一致之处进行管道胶带 - 因此我的选择是手动的数据组装,因为 HTTP 标准很少改变 :)
  2. 该解决方案不需要任何特殊的 HTML5 功能。
  3. 上面的例子使用jQuery.ajaxjQuery.extendjQuery.each

【讨论】:

  • 这是唯一对我有用的方法,可以从桌面上传文件并发布,非常感谢。
【解决方案6】:

是的,您可以将数据发布到像 here 这样的 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>

【讨论】:

    【解决方案7】:

    要使用 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有一个上传演示

    【讨论】:

      【解决方案8】:

      https://stackoverflow.com/a/16439233/68210 包含一个解决方案,如果您需要上传照片数据本身并且没有 URL,则该解决方案有效。

      【讨论】:

        【解决方案9】:

        这仍然有效。我使用它如下:

        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 for Facebook 相比,你们是否知道这样做是否可取或有很大的安全风险。

        【讨论】:

        • 如果将来有人需要它,此代码也适用于从 input[type=file] 上传文件。
        【解决方案10】:

        这行得通:

           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);
        };
        

        【讨论】:

        • 虽然这段代码可以回答这个问题,但最好包括对代码的作用的解释,以及为什么这是比其他答案更好的解决问题的方法。
        • 答案很好,但依赖于类型化数组,不全面支持。但实际上这个 sn-p 是我的灵感 answer
        【解决方案11】:

        我好像也遇到了类似的问题,但是上面的解决方法都没用。

        我使用 Arrabi 建议的解决方案(仅使用 url 属性)来发布图像,没有任何问题。我的图片每张大约 2-3 MB。

        当我将我的应用程序迁移到另一台服务器(更改帖子中我的图片的绝对 URL)时,该方法不断给我 324 错误,对于大约 100k 大小的图片。

        我认为这是由于我的一些 Apache 设置,但是当我将 apache 更改为 lighttpd 时,问题仍然存在。

        来自 Facebook 的连接实际上显示在我的 (apache) 日志中:

        69.171.234.7 - - [08/Jun/2012:11:35:54 +0200] "GET /images/cards/1337701633_518192458.png HTTP/1.1" 200 2676608 "-" "facebookplatform/1.0 (+http: //developers.facebook.com)"

        69.171.228.246 - - [08/Jun/2012:11:42:59 +0200] "GET /images/test5.jpg HTTP/1.1" 200 457402 "-" "facebookplatform/1.0 (+http:// developer.facebook.com)"

        69.171.228.246 - - [08/Jun/2012:11:43:17 +0200] "GET /images/test4.jpg HTTP/1.1" 200 312069 "-" "facebookplatform/1.0 (+http:// developer.facebook.com)"

        69.171.228.249 - - [08/Jun/2012:11:43:49 +0200] "GET /images/test2.png HTTP/1.1" 200 99538 "-" "facebookplatform/1.0 (+http:// developer.facebook.com)"

        69.171.228.244 - - [08/Jun/2012:11:42:31 +0200] "GET /images/test6.png HTTP/1.1" 200 727722 "-" "facebookplatform/1.0 (+http:// developer.facebook.com)"

        只有 test2.png 成功。

        【讨论】:

        • 这个问题是通过提高我的服务器的速度来解决的。它最初是 10Mbit 上行链路,现在是 100Mbit。显然,上传脚本在 facebook 端有超时。
        【解决方案12】:

        我使用以下内容分享照片(来自 Phaser 框架的一些 BitmapData)。它似乎工作......

        // Turn data URI to a blob ready for upload.
        dataURItoBlob(dataURI:string): Blob {
            var byteString = atob(dataURI.split(',')[1]);
            var ab = new ArrayBuffer(byteString.length);
            var ia = new Uint8Array(ab);
            for (var i = 0; i < byteString.length; i++) {
                ia[i] = byteString.charCodeAt(i);
            }
            return new Blob([ab], { type: 'image/jpeg' });
        }
        
        // Share the given bitmapData as a photo on Facebook
        sharePhoto(accessToken: string, photo: BitmapData, message: string): void {
            // Create form data, set up access_token, source and message
            var fd = new FormData();
            fd.append("access_token", accessToken);
            fd.append("source", this.dataURItoBlob(photo.canvas.toDataURL("image/jpeg")));
            fd.append("message", message);
        
            var request = new XMLHttpRequest();
            var thisPtr = this;
            request.onreadystatechange = function () {
                if (request.readyState == XMLHttpRequest.DONE) {
                    var json = JSON.parse(request.responseText);
                    if (json.hasOwnProperty("error")) {
                        var error = json["error"];
                        if (error.hasOwnProperty("type")) {
                            var errorType = error["type"];
                            if (errorType === "OAuthException") {
                                console.log("Need to request more permissions!");
                            }
                        }
                    }
                } else if (request.readyState == XMLHttpRequest.HEADERS_RECEIVED) {
        
                } else if (request.readyState == XMLHttpRequest.LOADING) {
        
                } else if (request.readyState == XMLHttpRequest.OPENED) {
        
                } else if (request.readyState == XMLHttpRequest.UNSENT) {
        
                }
            }
            request.open("POST", "https://graph.facebook.com/me/photos", true);
            request.send(fd);
        }
        

        【讨论】:

          【解决方案13】:

          如果有人还在寻找如何直接从画布上传到 Facebook 照片,这对我有用:

          function postImageToFacebook(token, imageData, message, successCallback, errorCallback) {
            var fd = new FormData();
            fd.append("access_token", token);
            fd.append("source", imageData);
            fd.append("caption", message);
          
            $.ajax({
                url: "https://graph.facebook.com/me/photos?access_token=" + token,
                type: "POST",
                data: fd,
                processData: false,
                contentType: false,
                cache: false,
                success: function (data) {
                  successCallback(data);
                },
                error: function (shr, status, data) {
                  errorCallback(data);
                },
                complete: function (data) {
                  console.log('Completed');
                }
            });
          }
          
          function dataURItoBlob(dataURI) {
            var byteString = atob(dataURI.split(',')[1]);
            var ab = new ArrayBuffer(byteString.length);
            var ia = new Uint8Array(ab);
            for (var i = 0; i < byteString.length; i++) {
                ia[i] = byteString.charCodeAt(i);
            }
            return new Blob([ab], {type: 'image/jpeg'});
          }
          

          使用它

          // *IMPORTANT*
          var FBLoginScope = 'publish_actions'; // or sth like 'user_photos,publish_actions' if you also use other scopes.
          
          var caption = "Hello Facebook!";
          var successCallback = ...;
          var errorCallback = ...;
          
          var data = $('#your_canvas_id')[0].toDataURL("image/jpeg");
          try {
            imageData = dataURItoBlob(data);
          } catch (e) {
            console.log(e);
          }
          
          FB.getLoginStatus(function (response) {
            if (response.status === "connected") {
              postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
            } else if (response.status === "not_authorized") {
              FB.login(function (response) {
                  postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
              }, {scope: FBLoginScope});
            } else {
              FB.login(function (response) {
                  postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
              }, {scope: FBLoginScope});
            }
          });
          

          修改自:http://gorigins.com/posting-a-canvas-image-to-facebook-and-twitter/

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多