转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)
http://blog.csdn.net/floodingfire/article/details/8142974
自动登录代码
- Weibo weibo = Weibo.getInstance();
- AccessToken accessToken = new AccessToken(accessToken, SINA_API_SECRET);
- accessToken.setExpiresIn("99999");
- weibo.setAccessToken(accessToken);
在使用新浪开放平台的OAuth2.0授权后自动登录时,一直在报同一个异常:
- com.weibo.net.WeiboException: HTTP/1.1 403 Forbidden
Step1:在LogCat下查看错误信息
- 11:00:03.129: W/System.err(557): com.weibo.net.WeiboException: HTTP/1.1 403 Forbidden (1. 未授权)
- 11:00:03.149: W/System.err(557): at com.weibo.net.Utility.openUrl(Utility.java:335) (2. 错误发生在这里)
- 11:00:03.149: W/System.err(557): at com.weibo.net.Utility.openUrl(Utility.java:286)
- 11:00:03.178: W/System.err(557): at com.weibo.net.Weibo.request(Weibo.java:149)
- 11:00:03.178: W/System.err(557): at com.weibo.net.AsyncWeiboRunner$1.run(AsyncWeiboRunner.java:51)
- 11:00:03.218: W/share(557): WeiboException: com.weibo.net.WeiboException: HTTP/1.1 403 Forbidden
首先错误消息是403状态码,有点儿常识的应该知道404代表没有访问资源、找不到资源等,而403大致是没有访问权、禁止访问等。(详细的解释Google之)
其实在新浪的文档和SDK的源码中都有关于异常的解释,比如在新浪SDK下,有这么一条注释:
com/weibo/net/WeiboException.java
- 403 Forbidden: 没有权限访问对应的资源.
可是明明传入了accessToken,怎么会没有访问权限呢?
不要急躁,顺着LogCat的信息顺藤摸瓜:StackTrace的栈顶信息显示错误最后出现在Utility.java中的openUrl()方法中:throw new WeiboException(String.format(status.toString()), statusCode);
- public static String openUrl(Context context, String url, String method,
- WeiboParameters params, String file, Token token) throws WeiboException {
- String result = "";
- try {
- HttpClient client = getNewHttpClient(context);
- HttpUriRequest request = null;
- ByteArrayOutputStream bos = null;
- if (method.equals("GET")) {
- url = url + "?" + encodeUrl(params);
- HttpGet get = new HttpGet(url);
- request = get;
- } else if (method.equals("POST")) {
- HttpPost post = new HttpPost(url);
- byte[] data = null;
- bos = new ByteArrayOutputStream(1024 * 50);
- if (!TextUtils.isEmpty(file)) {
- Utility.paramToUpload(bos, params);
- post.setHeader("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);
- Bitmap bf = BitmapFactory.decodeFile(file);
- Utility.imageContentToUpload(bos, bf);
- } else {
- post.setHeader("Content-Type", "application/x-www-form-urlencoded");
- String postParam = encodeParameters(params);
- data = postParam.getBytes("UTF-8");
- bos.write(data);
- }
- data = bos.toByteArray();
- bos.close();
- // UrlEncodedFormEntity entity = getPostParamters(params);
- ByteArrayEntity formEntity = new ByteArrayEntity(data);
- post.setEntity(formEntity);
- request = post;
- } else if (method.equals("DELETE")) {
- request = new HttpDelete(url);
- }
- setHeader(method, request, params, url, token);
- HttpResponse response = client.execute(request);
- StatusLine status = response.getStatusLine();
- int statusCode = status.getStatusCode();
- if (statusCode != 200) {
- result = read(response);
- throw new WeiboException(String.format(status.toString()), statusCode);
- }
- // parse content stream from response
- result = read(response);
- return result;
- } catch (IOException e) {
- throw new WeiboException(e);
- }
- }
可以看到请求完毕以后,判断statusCode不为200(请求正常)状态码。也就是错误出现在发送请求之前,继续往上看,这个方法用的是Android中常用的一种网络通信方法:
- HttpResponse response = client.execute(request);
- setHeader(method, request, params, url, token);
- // 设置http头,如果authParam不为空,则表示当前有token认证信息需要加入到头中
- public static void setHeader(String httpMethod, HttpUriRequest request,
- WeiboParameters authParam, String url, Token token) throws WeiboException {
- if (!isBundleEmpty(mRequestHeader)) {
- for (int loc = 0; loc < mRequestHeader.size(); loc++) {
- String key = mRequestHeader.getKey(loc);
- request.setHeader(key, mRequestHeader.getValue(key));
- }
- }
- if (!isBundleEmpty(authParam) && mAuth != null) {
- String authHeader = mAuth.getWeiboAuthHeader(httpMethod, url, authParam,
- Weibo.getAppKey(), Weibo.getAppSecret(), token);
- if (authHeader != null) {
- request.setHeader("Authorization", authHeader);
- }
- }
- request.setHeader("User-Agent", System.getProperties().getProperty("http.agent")
- + " WeiboAndroidSDK");
- }
- private static HttpHeaderFactory mAuth;
- public static void setAuthorization(HttpHeaderFactory auth) {
- mAuth = auth;
- }
国内的大平台如新浪、腾讯、人人一贯如此,强内聚、弱耦合似乎只是个说法而已,虽然说一个大项目要做好扩展,但是好歹也要给个提示嘛!!!
Step3:解决问题
好了,小小的抱怨一下,我们的任务还没有完成,大致思路明确,要在此方法前初始化mAuth参数。
可是,参数是HttpHeaderFactory 对象啊,跟代码过去一看,又傻了:
- public abstract class HttpHeaderFactory {
- public static final String CONST_HMAC_SHA1 = "HmacSHA1";
- public static final String CONST_SIGNATURE_METHOD = "HMAC-SHA1";
- public static final String CONST_OAUTH_VERSION = "1.0";
- public HttpHeaderFactory() {
- }
- ...
HOLD住,冲动易怒可不是好程序员的特质!既然是用的抽象类,那么前面的错误也明了,写这个代码的人可能是为了扩展性,既然是这样,他可能写好了实现类。如果连实现类都没有,大家就尽情的愤怒,然后安静的自己实现一个吧。
方案一:自己实现
....我这么懒,是不会做这种傻事的。
方案二:查找实现类
怎么个查找法?把所有的类都看一遍,看看是不是 extends HttpHeaderFactory? 是这么想的童鞋,先去面壁5分钟。
...
ok,有经验的程序员应该知道,在Eclipse中查看继承关系是有快捷方式的,选中类以后按:Ctrl + T。
这一下又要犯愁了,一下子揪出了他一家子,可见这个程序员确实是为了扩展,但是这么多的子类,到底用哪一个好呢?
你可以一个个看看,但是我用的是OAuth2.0,直接用试试Oauth2AccessTokenHeader好了。看着注释里那个半吊子英语,我又笑了~~should not be...
- /**
- * Encapsulation a http accessToken headers. the order of weiboParameters will not be changed.
- * Otherwise the signature <strong>should not be</strong> calculated right.
- * @author ZhangJie (zhangjie2@staff.sina.com.cn)
- */
- public class Oauth2AccessTokenHeader extends HttpHeaderFactory {
- @Override
- public String getWeiboAuthHeader(String method, String url, WeiboParameters params,
- String app_key, String app_secret, Token token) throws WeiboException {
- if(token == null){
- return null;
- }
- return "OAuth2 " + token.getToken();
- }
- @Override
- public WeiboParameters generateSignatureList(WeiboParameters bundle) {
- return null;
- }
- @Override
- public String generateSignature(String data, Token token) throws WeiboException{
- return "";
- }
- @Override
- public void addAdditionalParams(WeiboParameters des, WeiboParameters src) {
- // TODO Auto-generated method stub
- }
- }
- Utility.setAuthorization(new Oauth2AccessTokenHeader());
附录
正确的自动登录方法为:
- Weibo weibo = Weibo.getInstance();
- Utility.setAuthorization(new Oauth2AccessTokenHeader());
- AccessToken accessToken = new AccessToken(accessToken, SINA_API_SECRET);
- accessToken.setExpiresIn("99999");
- weibo.setAccessToken(accessToken);