上传Base64图片Facebook Graph API

22

我正在尝试使用Node.js将一个base64图片上传到Facebook页面。我已经成功地使用了所有的多部分数据等将其上传,但是如果我应该从文件系统中读取文件(即使用fs.readFileSync('c:\a.jpg')),那么该怎么办?

然而,如果我使用base64编码的图像并尝试上传它,它会给我以下错误:{"error":{"message":"(#1) An unknown error occurred","type":"OAuthException","code":1}}

我已经尝试通过new Buffer(b64string, 'base64');将其转换为二进制并上传,但没有成功。

我已经苦恼了3天,所以任何帮助都将不胜感激。

编辑: 如果有人知道我如何将base64转换为二进制并成功上传它,那对我也起作用。

编辑: 代码片段

var postDetails = separator + newlineConstant + 'Content-Disposition: form-data;name="access_token"' + newlineConstant + newlineConstant + accessToken + newlineConstant + separator;

postDetails = postDetails + newlineConstant + 'Content-Disposition: form-data; name="message"' + newlineConstant + newlineConstant + message + newlineConstant;

//Add the Image information
var fileDetailsString = '';
var index = 0;
var multipartBody = new Buffer(0);
images.forEach(function (currentImage) {
    fileDetailsString = fileDetailsString + separator + newlineConstant + 'Content-Disposition: file; name="source"; filename="Image' + index + '"' + newlineConstant + 'Content-Type: image/jpeg' + newlineConstant + newlineConstant;
    index++;

    multipartBody = Buffer.concat([multipartBody, new Buffer(fileDetailsString), currentImage]); //This is what I would use if Bianry data was passed in 

    currentImage = new Buffer (currentImage.toString('base64'), 'base64'); // The following lines are what I would use for base64 image being passed in (The appropriate lines would be enabled/disabled if I was using Binary/base64)
    multipartBody = Buffer.concat([multipartBody, new Buffer(fileDetailsString), currentImage]);
});

multipartBody = Buffer.concat([new Buffer(postDetails), multipartBody, new Buffer(footer)]);

b64String是从哪里来的?你确定它不是一个数据URL吗?如果你使用console.log(b64string),请展示一些示例数据。 - loganfsmyth
你能提供通过JavaScript Ajax上传Base64的示例吗? - Brune
嘿,大家好,抱歉回复晚了...我离开了。这绝对不是数据URL...这里是数据开头的一小段.../9j/4AAQSkZJRgABAQEASABIAAD/2wBDABcQERQRDhcUEhQaGBcbIjk@Brune 我已经更新了帖子,放了上传部分的片段。多部分数据等都可以正常工作,当我传递二进制图像时,一切都正常工作,但当我传递base64图像时,它就无法工作。 - Mauro
这与Node.js有关吗?我有一个base64图像数据并且在ajax请求的结构方面遇到了困难(header和body中应该放什么)。。我得到了“无效请求”错误。 - Brune
7个回答

24

我希望这对你有用。通过使用JavaScript仅上传照片到FB,您可以使用以下方法。在此处所需的是图像数据(即图像的base64格式)和mime类型。

try {
    blob = dataURItoBlob(imageData,mimeType);
} catch (e) {
    console.log(e);
}

var fd = new FormData();
fd.append("access_token",accessToken);
fd.append("source", blob);
fd.append("message","Kiss");

try {
   $.ajax({
        url:"https://graph.facebook.com/" + <<userID received on getting user details>> + "/photos?access_token=" + <<user accessToken>>,
        type:"POST",
        data:fd,
        processData:false,
        contentType:false,
        cache:false,
        success:function(data){
            console.log("success " + data);
        },
        error:function(shr,status,data){
            console.log("error " + data + " Status " + shr.status);
        },
        complete:function(){
            console.log("Ajax Complete");
        }
   });

} catch(e) {
    console.log(e);
}

function dataURItoBlob(dataURI,mime) {
    // convert base64 to raw binary data held in a string
    // doesn't handle URLEncoded DataURIs

    var byteString = window.atob(dataURI);

    // separate out the mime component


    // write the bytes of the string to an ArrayBuffer
    //var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    // write the ArrayBuffer to a blob, and you're done
    var blob = new Blob([ia], { type: mime });

    return blob;
}

//编辑 AJAX 语法


3
好的,没问题。当你将其发送进行blob转换时,需要删除"data:image/png;base64,"部分。是的,它运作良好。 - Brune
1
哇塞,这个好使了!在这里抱怨之前应该再调整一下。你真是个奇迹般的工作者! - Justin McCraw
希望有人能看到这个!我正在尝试做同样的事情,但是每次从Facebook返回我的FormData时都会显示空数组并出现错误。有什么想法吗?! - Lagoo87
你收到了什么错误信息?你的意思是说你的表单数据没有传递到Facebook吗? - Brune
我曾尝试使用FB.api(),但没有成功。现在,我测试了这段代码,它可以工作!太棒了!谢谢 :) - Pedro Souza
显示剩余4条评论

14

对我来说,上面的代码没能正常工作(在type:"POST",之后缺少逗号,并且数据URI转换为Blob函数报告了错误)。我在Firefox和Chrome中使用下面的代码可以正常工作:

function PostImageToFacebook(authToken)
{
    var canvas = document.getElementById("c");
    var imageData  = canvas.toDataURL("image/png");
    try {
        blob = dataURItoBlob(imageData);
    }
    catch(e) {
        console.log(e);
    }
    var fd = new FormData();
    fd.append("access_token",authToken);
    fd.append("source", blob);
    fd.append("message","Photo Text");
    try {
        $.ajax({
            url:"https://graph.facebook.com/me/photos?access_token=" + authToken,
            type:"POST",
            data:fd,
            processData:false,
            contentType:false,
            cache:false,
            success:function(data){
                console.log("success " + data);
            },
            error:function(shr,status,data){
                console.log("error " + data + " Status " + shr.status);
            },
            complete:function(){
                console.log("Posted to facebook");
            }
        });
    }
    catch(e) {
        console.log(e);
    }
}

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/png' });
}

这是GitHub上的代码 https://github.com/DanBrown180/html5-canvas-post-to-facebook-base64


2
我已经尝试了你的代码,我的与Facebook的通信似乎正在工作,但是我有一个问题,fd(FormData)为空,只显示空数组。 有什么想法吗? - Lagoo87

2
我们可以通过使用现代的Fetch API来简化图像重新编码,而不是使用Uint8Array。
 var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="

 fetch(url)
  .then(res => res.blob())
  .then(blob => console.log(blob))`

唯一的问题是它是一个实验性功能(https://caniuse.com/#feat=mdn-api_body_blob)。因此在生产环境中使用时要小心。 - codeinaire

2
丹的答案最好。在这种情况下可能有用的另一个东西是发布照片的可选参数:“no_story”。此参数默认为true,强制照片发布跳过用户的墙壁。通过添加此参数可以避免这种情况。

fd.append("no_story", false);

您可以使用照片帖子更新用户的墙。我本来想留下评论的,但是需要50点声望才能评论。

那听起来像是一个重要的功能!嘿...你需要在这里花更多的时间! - Alexis Wilke

1
以下是我如何使用Facebook JS API发布图片的方法。 我使用了canvas HTML5功能。它并不被每个浏览器完全支持。
首先,您需要获取图像数据,并将其封装在表单数据中。 然后,我使用FB.login API来检索访问令牌和用户ID。
          var data = $('#map >> canvas').toDataURL('image/png');
          var blob;
          try {
            var byteString = atob(data.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);
            }
            blob = new Blob([ab], {type: 'image/png'});
          } catch (e) {
            console.log(e);
          }
          var fd = new FormData();
          fd.append("source", blob);
          fd.append("message", "Photo Text");
          FB.login(function(){
            var auth = FB.getAuthResponse();
            $.ajax({
              url:"https://graph.facebook.com/"+auth.userID+"/photos?access_token=" + auth.accessToken,
              type:"POST",
              data:fd,
              processData:false,
              contentType:false,
              cache:false,
              success:function(data){
                console.log("success " + data);
              },
              error:function(shr,status,data){
                console.log("error " + data + " Status " + shr.status);
              },
              complete:function(){
                console.log("Ajax Complete");
              }
            });
          }, {scope: 'publish_actions'});

这很棒,因为您向我们展示了如何获取实际的授权参数以联系Facebook。 - Alexis Wilke

1
我曾经做过和你的问题非常相似的事情。我有一个需要POST到Facebook粉丝页面的网络摄像头快照。这个设置在一个餐厅里,人们可以拍照并将其发布到餐厅页面上。然后人们会看到一张带有QR码的Facebook照片,他们可以选择在自己的个人资料上分享。希望这能帮助一些人,因为我搜索了很多才找到这个可行的解决方案。
注意:我的图像已经被BASE64编码了。
//imageData is a base64 encoded JPG
function postSocial(imageData, message){       
        var ia = toUInt8Array(imageData);
        postImageToFacebook(mAccessTokenPage, "imageName", "image/jpeg",ia, message);
}

function toUInt8Array(dataURI) {
        // convert base64 to raw binary data held in a string
        // doesn't handle URLEncoded DataURIs
        var byteString = window.atob(dataURI);

        // write the bytes of the string to an ArrayBuffer
        //var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
        return ia;
    }

function postImageToFacebook( 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/ + {PAGE_ID} + "/photos?access_token=" + authToken, true );
        xhr.onload = function() {
            // ... Fill in your own
            //Image was posted 
           console.log(xhr.responseText);
        };
        xhr.onerror = function(){
            console.log("Error while sending the image to Facebook");
        };
        xhr.setRequestHeader( "Content-Type", "multipart/form-data; boundary=" + boundary );
        xhr.sendAsBinary( formData );
    }

1

这里有一个例子,不需要jQuery或其他库,只需要原生的Fetch API:

const dataURItoBlob = (dataURI) => {
    let byteString = atob(dataURI.split(',')[1]);
    let ab = new ArrayBuffer(byteString.length);
    let ia = new Uint8Array(ab);
    for (let i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ia], {
        type: 'image/jpeg'
    });
}
const upload = async (response) => {
    let canvas = document.getElementById('canvas');
    let dataURL = canvas.toDataURL('image/jpeg', 1.0);
    let blob = dataURItoBlob(dataURL);
    let formData = new FormData();
    formData.append('access_token', response.authResponse.accessToken);
    formData.append('source', blob);

    let responseFB = await fetch(`https://graph.facebook.com/me/photos`, {
        body: formData,
        method: 'post'
    });
    responseFB = await responseFB.json();
    console.log(responseFB);
};
document.getElementById('upload').addEventListener('click', () => {
    FB.login((response) => {
        //TODO check if user is logged in and authorized publish_actions
        upload(response);
    }, {scope: 'publish_actions'})
})

来源:http://www.devils-heaven.com/facebook-javascript-sdk-photo-upload-from-canvas/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接