新浪微博 OAuth2 NodeJs发微博

想用nodejs写个微博客户端发微博,无奈新浪微博的nodejs sdk是OAuth1.0的。
只能自己根据OAuth1.0 改了改。
只写了statuses/update 和 statuses/upload,其他的实现基本都类似了。
update是简单参数的post,upload是multipart 包含二进制图片的post。
改改帐号参数和发送的图片路径,node weibotest.js就能成功发送了。
如果中文出现乱码,请把这两个js文件保存成utf-8编码。


weibo.js
var querystring = require('querystring'),
crypto = require('crypto'),
https = require('https'),
URL = require('url'),
path = require('path'),
fs = require('fs');

var apiprefix = 'https://api.weibo.com/2/',
appkey = '2849184197',
appsecret = '7338acf99a00412983f255767c7643d0';
var userId = "微博帐号",
passwd = "微博密码";

var baseurl = "https://api.weibo.com/2/";

var weibo = module.exports = function() {
    this._accesstoken = "";
    this._accessTokenName = "access_token";
};
weibo.prototype = {
		//oauth2/authorize
    getAuthorize: function(callback) {
        var params = {};
        params['client_id'] = appkey; // appkey
        params['redirect_uri'] = ""; // oauth2 回调地址
        params['response_type'] = "code";
        params['action'] = "submit";
        params['userId'] = userId; // 微博帐号
        params['passwd'] = passwd; // 帐号密码
        var post_data = querystring.stringify(params);
        var post_headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        };
        var url = apiprefix + "oauth2/authorize";
        //https request
        var m = "POST";
        var code = "";
        var tt = this;
        this._request(m, url, post_headers, post_data, null,
        function(error, body, response) {
            if (error) {
                console.log("error:" + error);
            }
            else {
                code = response.headers.location.substr(6);
                console.log("code:" + code);
                tt.getAccesstoken(code,
                function(err, access_token, refresh_token) {
                    console.log(access_token);
                    tt._accesstoken = access_token;
                    callback(err, access_token, refresh_token);
                });
            }
        });
    },
    //oauth2/access_token
    getAccesstoken: function(code, callback) {
        var params = {};
        params['grant_type'] = "authorization_code"; // appkey
        params['redirect_uri'] = ""; // oauth2 回调地址
        params['client_id'] = appkey;
        params['client_secret'] = appsecret;
        params['code'] = code;

        var post_data = querystring.stringify(params);
        var post_headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            "contentType":"text/html;charset=uft-8"
        };
        var url = apiprefix + "oauth2/access_token";
        //https request
        var m = "POST";
        this._request(m, url, post_headers, post_data, null,
        function(error, data, response) {
            if (error) callback(error);
            else {
                var results;
                try {
                    // As of http://tools.ietf.org/html/draft-ietf-oauth-v2-07
                    // responses should be in JSON
                    results = JSON.parse(data);
                }
                catch(e) {
                    // .... However both Facebook + Github currently use rev05 of the spec
                    // and neither seem to specify a content-type correctly in their response headers :(
                    // clients of these services will suffer a *minor* performance cost of the exception
                    // being thrown
                    results = querystring.parse(data);
                }
                var access_token = results["access_token"];
                var refresh_token = results["refresh_token"];
                delete results["refresh_token"];
                callback(null, access_token, refresh_token);
            }
        });
    },
    //通用https request,从node-oauth上oauth2摘出来的
    _request: function(method, url, headers, post_body, access_token, callback) {
        var creds = crypto.createCredentials({});
        var parsedUrl = URL.parse(url, true);
        if (parsedUrl.protocol == "https:" && !parsedUrl.port) parsedUrl.port = 443;

        var realHeaders = {};
        if (headers) {
            for (var key in headers) {
                realHeaders[key] = headers[key];
            }
        }
        realHeaders['Host'] = parsedUrl.host;

        if (Buffer.isBuffer(post_body)) {
            realHeaders['Content-Length'] = post_body ? post_body.length: 0;
        }
        else {
            realHeaders['Content-Length'] = post_body ? Buffer.byteLength(post_body) : 0;
        }
        if (access_token) {
            if (!parsedUrl.query) parsedUrl.query = {};
            parsedUrl.query[this._accessTokenName] = access_token;
        }

        var result = "";
        var queryStr = querystring.stringify(parsedUrl.query);
        if (queryStr) queryStr = "?" + queryStr;
        var options = {
            host: parsedUrl.hostname,
            port: parsedUrl.port,
            path: parsedUrl.pathname + queryStr,
            method: method,
            headers: realHeaders
        };
        // Some hosts *cough* google appear to close the connection early / send no content-length header
        // allow this behaviour.
        var allowEarlyClose = false;
        var callbackCalled = false;
        function passBackControl(response, result) {
            if (!callbackCalled) {
                callbackCalled = true;
                if (response.statusCode != 200 && (response.statusCode != 301) && (response.statusCode != 302)) {
                    callback({
                        statusCode: response.statusCode,
                        data: result
                    });
                } else {
                    callback(null, result, response);
                }
            }
        }
        console.log("options:");
        console.log(options);
        var request = https.request(options,
        function(response) {
            response.on("data",
            function(chunk) {
                result += chunk
            });
            response.on("close",
            function(err) {
                if (allowEarlyClose) {
                    passBackControl(response, result);
                }
            });
            response.addListener("end",
            function() {
                passBackControl(response, result);
            });
        });
        request.on('error',
        function(e) {
            callbackCalled = true;
            callback(e);
        });
        if (method == 'POST' && post_body) {
            request.write(post_body);
        }
        request.end();
    },
    //普通post,执行类似statuses/update.json
    post: function(url, params, callback) {
        if (!this._accesstoken) return callback("not authorize");
        var post_data = querystring.stringify(params);
        var post_headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        };
        if (params.ContentType) {
            post_headers['Content-Type'] = params.ContentType;
        }
        this._request("POST", baseurl + url + '.json', post_headers, post_data, this._accesstoken, callback);
    },
    /********** statuses *********/
    //statuses/repost 转发一条微博信息
    //statuses/destroy 删除微博信息
    //statuses/update 发布一条微博信息
    //statuses/upload 上传图片并发布一条微博
    //statuses/upload_url_text 发布一条微博同时指定上传的图片或图片url 
    //emotions 获取官方表情
    repost: function(args, callback) {
        /* args参数:
		 * 	id : 微博id
		 * 	status : 转发文本 
		 * 	is_comment 0-不发评论 1-发评论给当前微博 2-发评论给原微博 3-都发
		 */
        if (!args.id) return callback('missing argument id');
        this.post('statuses/repost', args, callback);
    },

    update: function(params, callback) {
        if (!params.status) return callback('missing argument status');
        this.post('statuses/update', params, callback);
    },

    FILE_CONTENT_TYPES: {
        '.gif': 'image/gif',
        '.jpeg': 'image/jpeg',
        '.jpg': 'image/jpeg',
        '.png': 'image/png'

    },
		//获取文件信息,用于statuses/upload 上传图片并发布一条微博
    fileinfo: function(file) {
        var name, content_type;
        if (typeof(file) === 'string') {
            var ext = path.extname(file);
            content_type = this.FILE_CONTENT_TYPES[ext];
            name = path.basename(file);
        } else {
            name = file.name || file.fileName;
            content_type = file.fileType || file.type;
        }
        return {
            name: name,
            content_type: content_type
        };
    },

    /** 
     * 上传图片
     * pic: filepath
     * callback: finish callback function
     **/
    upload: function(params, callback) {
        if (!params.status) return callback('missing argument status');
        var pic = params.pic;
        var pic_field = 'pic';

        var boundary = 'boundary' + (new Date).getTime();
        var dashdash = '--';
        var crlf = '\r\n';

        /* Build RFC2388 string. */
        var builder = '';

        builder += dashdash;
        builder += boundary;
        builder += crlf;
				//微博文字
        builder += 'Content-Disposition: form-data; name="status"';
        builder += crlf;
        builder += crlf;
        /* Append form data. */
        builder += params.status;
        builder += crlf;

        /* Write boundary. */
        builder += dashdash;
        builder += boundary;
        builder += crlf;

        var fileinfo = this.fileinfo(pic);

        /* Generate headers. [PIC] */
        builder += 'Content-Disposition: form-data; name="' + pic_field + '"';

        builder += '; filename="' + fileinfo.name + '"';
        builder += crlf;

        builder += 'Content-Type: ' + fileinfo.content_type + ';';
        builder += crlf;
        builder += crlf;

        var tt = this;
        // 处理文件内容
        //微博图片
        this.read_file(pic,
        function(file_buffer) {
            var endstr = crlf + dashdash + boundary + dashdash + crlf,
            buffer = null;
            if (typeof(BlobBuilder) === 'undefined') {
                var builderLength = new Buffer(builder).length;
                var size = builderLength + file_buffer.length + endstr.length;
                buffer = new Buffer(size);
                var offset = 0;
                buffer.write(builder);
                offset += builderLength;
                file_buffer.copy(buffer, offset);
                offset += file_buffer.length;
                buffer.write(endstr, offset);
            } else {
                buffer = new BlobBuilder(); //NOTE WebKitBlogBuilder
                buffer.append(builder);
                buffer.append(pic);
                buffer.append(endstr);
                buffer = buffer.getBlob();
            }
            if (!tt._accesstoken) return callback("not authorize");
            var post_data = buffer;
            //必须使用multipart/form-data
            var post_headers = {
                'Content-Type': 'multipart/form-data;boundary=' + boundary
            };
            console.log(builder);
            tt._request("POST", baseurl + 'statuses/upload' + '.json', post_headers, post_data, tt._accesstoken, callback);

        });
    },

    read_file: function(pic, callback) {
        if (typeof(pic) === 'string') {
            fs.stat(pic,
            function(err, stats) {
                fs.readFile(pic,
                function(err, file_buffer) {
                		console.log(err);
                  	if (!err) callback(file_buffer);
                });
            });
        } else {
            callback(pic);
        }
    },

};


weibotest.js

var weibo = require('./weibo');

var wb = new weibo();
wb.getAuthorize(function(err, access_token, refresh_token) {
    //wb.update({
    //    "status": "中文不行?"
    //},
    //function(error, body, response) {
    //    if (error) {
    //        console.log("error:");
    //        console.log(error);
    //    }
    //    else {
    //        console.log("body:" + body);
    //    }
    //});
    wb.upload({
        "status": "中文不行?",
        "pic": "E:/XX.jpg"
    },
    function(error, body, response) {
        if (error) {
            console.log("error:");
            console.log(error);
        }
        else {
            console.log("body:" + body);
        }
    });
});


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值