Facebook Graph API - 使用 JavaScript 上传照片

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4999024/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 15:09:45  来源:igfitidea点击:

Facebook Graph API - upload photo using JavaScript

javascriptfacebookfacebook-graph-apifile-upload

提问by Moz

Is it possible to upload a file using the Facebook Graph API using javascript, I feel like I'm close. I'm using the following JavaScript

是否可以使用 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!');
        }
    }); 
}

Upon running this I receive the following error...

运行此程序后,我收到以下错误...

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

When I try and research this method all I can find out about is a php method that apears to solve this

当我尝试研究这种方法时,我只能找到一种可以解决此问题的 php 方法

$facebook->setFileUploadSupport(true);

However, I am using JavaScript, it looks like this method might be to do with Facebook Graph permissions, but I already have set the permissions user_photos and publish_stream, which I believed are the only ones I should need to perform this operation.

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

I have seen a couple of unanswered questions regarding this on stackoverflow, hopefully I can explained myself enough. Thanks guys.

我在 stackoverflow 上看到了几个与此相关的悬而未决的问题,希望我能对自己进行足够的解释。谢谢你们。

采纳答案by David Bullock

EDIT: this answer is (now) largely irrelevant. If your image is on the web, just specify the urlparam as per the API(and see examples in other answers). If you would like to POST the image content to facebook directly, you may want to read this answer to gain understanding. Also see HTML5's Canvas.toDataUrl().

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

The API says: "To publish a photo, issue a POST request with the photo file attachment as multipart/form-data."

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

FB is expecting that the bytes of the image to be uploaded are in the body of the HTTP request, but they're not there. Or to look at it another way - where in the FB.api() call are you supplying the actual contents of the image itself?

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

The FB.api()API is poorly documented, and doesn't supply an example of an HTTP POST which includes a body. One might infer from the absence of such an example that it doesn't support this.

所述FB.api()API记录不当,并且不提供的HTTP POST,其包括主体的一个例子。人们可能会从没有这样一个例子中推断出它不支持这一点。

That's probably OK - FB.api() is using something called XmlHttpRequestunder the covers which doessupport including a body ... look it up in your favourite JavaScript reference.

这可能没问题 - FB.api() 正在使用一些称为undercovers 的东西XmlHttpRequest,它确实支持包含一个主体......在你最喜欢的 JavaScript 参考中查找它。

However, you'll still have 2 sub-problems to solve:

但是,您仍然需要解决 2 个子问题:

  1. how to prepare the image bytes (and rest of the request) as multipart/form-data; and
  2. getting the bytes of the image itself
  1. 如何将图像字节(以及请求的其余部分)准备为multipart/form-data;和
  2. 获取图像本身的字节

(incidentally, the need to encode the message body is probably what the PHP setFileUploadSupport(true) method is for - tell the facebookobject to encode the message body as multipart/form-databefore sending)

(顺便说一句,对消息正文进行编码的需要可能是 PHP setFileUploadSupport(true) 方法的用途 - 告诉facebook对象multipart/form-data在发送之前对消息正文进行编码)

But it's a bit meessier than that

但它比那更混乱

Unfortunately, sub-problem '2' may bite you - there is no way (last time I looked) to extract the bytes of an image from the browser-supplied Image object.

不幸的是,子问题 '2' 可能会咬你 - 没有办法(我上次看)从浏览器提供的 Image 对象中提取图像的字节。

If the image to be uploaded is accessible via a URL, you could fetch the bytes with XmlHttpRequest. Not too bad.

如果可以通过 URL 访问要上传的图像,则可以使用 XmlHttpRequest 获取字节。还不错。

If the image is coming from the user's desktop, your probable recourse is to offer the user a:

如果图像来自用户的桌面,您可能的方法是为用户提供:

 <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> 

(notice that sourcereferences the name given to the file-upload widget)

(注意source引用了文件上传小部件的名称)

... and hope that FB anticipated receiving the data in this manner (try it with a static HTML form first, before coding it up dynamically in JS). One might infer that in fact it would, since they don't offer another means of doing it.

...并希望 FB 预期以这种方式接收数据(先尝试使用静态 HTML 表单,然后再在 JS 中对其进行动态编码)。人们可能会推断,事实上它会,因为他们没有提供另一种方法来做到这一点。

回答by Владимир Дворник

Yes, this is possible, i find 2 solutions how to do that and they are very similar to each other, u need just define url parameter to external image url

是的,这是可能的,我找到了 2 个解决方案,它们彼此非常相似,您只需将 url 参数定义为外部图像 url

FIRST one using Javascript SDk:

第一个使用 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);
    }

});

and SECOND one using jQuery Post request and FormData:

使用第二个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");
                    }
                });

回答by Arrabi

i used @Владимир Дворник code with some modification, I had the same issue and with this code it worked very well:

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

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

        });

回答by sumitkanoje

Photos can be uploaded to facebook profile using Ajax as follows.

照片可以使用 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"); }
            });

So this is the best way to post photo to a facebook profile with GRAPH API and is the simple one.

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

In many answer i have seen that image url is shwon by the source,picture or image etc but that doesn't works.

在许多答案中,我看到图像 url 是由来源、图片或图像等提供的,但这不起作用。

The use of of source,picture or image leads to a (#324) Requires upload fileerror .

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

Best way to avoid the 324 error.

避免 324 错误的最佳方法。

回答by Matyas

Only @Thiago's answer is answering the question of uploadingdata via javascript. I've found that the Facebook JS API doesn't cover this situation.

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

I've also brew & tested my personl solution.

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

Main steps

主要步骤

  1. Get the binary data of the image (I've used a canvas, but using an input box is possible as well)
  2. Form a multipart request with all necesarry data for the graph API call
  3. Include the binary data in the request
  4. Encode everything in a binary array and send it so via XHR
  1. 获取图像的二进制数据(我使用了画布,但也可以使用输入框)
  2. 使用图形 API 调用的所有必要数据形成多部分请求
  3. 在请求中包含二进制数据
  4. 将所有内容编码为二进制数组并通过 XHR 发送

Code

代码

Conversion utilities

转换实用程序

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

Image posting snippet

图片发布片段

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

Usage

用法

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

额外的

Extracting the binary string representation of a canvas image

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

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

Information on how to load the binaryString from an input[type=file]

有关如何从 input[type=file]

HTML5 File API read as text and binary

HTML5 文件 API 读取为文本和二进制

Notes:

笔记:

  1. There are of course alternative approaches as well
    • Using an HTML form in an iframe - you cannot get the response from the call
    • Using a FormData& Fileapproach, but unfortunately in this case there are a lot of incompatilities which make the process harder to use, and you would end up duct-taping around the inconsistencies - thus my choice was manual data assembly since HTTP standards rarely change :)
  2. The solution does not require any special HTML5 features.
  3. The above example uses jQuery.ajax, jQuery.extend, jQuery.each
  1. 当然也有替代方法
    • 在 iframe 中使用 HTML 表单 - 您无法从调用中获得响应
    • 使用FormData&File方法,但不幸的是,在这种情况下,有很多不兼容性使该过程更难使用,并且您最终会围绕不一致性进行管道录音 - 因此我的选择是手动数据组装,因为 HTTP 标准很少改变:)
  2. 该解决方案不需要任何特殊的 HTML5 功能。
  3. 上面的例子使用jQuery.ajax, jQuery.extend,jQuery.each

回答by Guilherme Torres Castro

Yes, you can do this posting data to an iframe like here, or you can use jQuery File Upload. The problem is you can't get response from iframe, using plugin you can use a page handle.

是的,您可以像这里一样将数据发布到 iframe ,或者您可以使用jQuery File Upload。问题是您无法从 iframe 获得响应,使用插件您可以使用页面句柄。

Example: upload a video using jQuery File Upload

示例:使用 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>

回答by Drew

To upload a file from the local computer with just Javascript try HelloJS

要仅使用 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>

There's an upload demo at http://adodson.com/hello.js/demos/upload.html

http://adodson.com/hello.js/demos/upload.html上有一个上传演示

回答by Daniel X Moore

https://stackoverflow.com/a/16439233/68210contains a solution that works if you need to upload the photo data itself and don't have a url.

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

回答by Carmela

This still works. I am using it as below:

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

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

I have to ask though if you people have any idea if this is advisable or has a big security risk compared to using PHP api for Facebook.

不过,我不得不问一下,与将 PHP api 用于 Facebook 相比,你们是否知道这是否可取或具有很大的安全风险。

回答by Thiago Tecedor

This works:

这有效:

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