网页版本微信通讯协议分析

        没事分析了下网页版本微信的通训协议,并且用java实现了登录,发送和接收消息,以后可以用来集成到后台,作为一个业务通知系统,就是每次登录需要扫码比较费事。

登录步骤:

1.打开首页,分配一个随机用户id,

2.根据该id获取二维码图片。

3.微信客户端扫描该图片,在客户端确认登录。

4.浏览器不停的调用一个接口,如果返回登录成功,则调用登录接口

5.此时可以获取联系人列表,可以发送消息。然后不断调用同步接口。

6.如果同步接口有返回,则可以获取新消息,然后继续调用同步接口。

贴上源码,仅供参考:(需要下载apache httpclient以及json)

package wwx;

import java.util.LinkedList;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class WebWeixin {
	String url_getuuid="https://login.weixin.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={t}";
	
	String url_login2weima="https://login.weixin.qq.com/qrcode/{}?t=webwx";
	
	String url_check_login="https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?uuid={}&tip=1&_={t}";
	
	String url_init = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r={t}";
	
	String url_contactlist = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?r={t}";
	
	String url_synccheck = "https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?callback=jQuery18309326978388708085_1377482079946&r={t}&sid={0}&uin={1}&deviceid={2}&synckey={3}&_={t}";
	
	String url_msglist = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={}&r={t}";
	
	String url_sendMsg = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?sid={}&r={t}";
	public static void main(String[] args) throws Exception{
		new WebWeixin().init();
//		new Test().getCookies("http://www.baidu.com");
//		System.out.println(System.currentTimeMillis(););
	}
	
	class UInfo{
		 String wxuin;
		 String wxsid;
		 String webwxuvid; 
		 String deviceid;
		 
		 String syncKey;
		 JSONObject SyncKey;
		 
		 String SKey;
		 
		 JSONObject ujson;
		 String name;	//帐号
		 String nickName;//昵称
		 
		 boolean connect = false;
	}
	UInfo u = new UInfo();
	Object wait = new Object();
	
	LinkedList<WxMsgListener> listeners = new LinkedList<WxMsgListener>();
	public void addListener(WxMsgListener lis){
		this.listeners.add(lis);
	}
	//开始登录微信
	public void start(){
		//1.取得uuid
		String getUUIDUrl = url_getuuid.replace("{t}", ""+System.currentTimeMillis());
		 String res = Utils.getUrl(getUUIDUrl);
		 
		 String uuid = "";
		 Pattern pat = Pattern.compile("window.QRLogin.code = ([0-9]+); window.QRLogin.uuid = \"([0-9a-z]+)\";");  
		 Matcher mat = pat.matcher(res);  
		 if(mat.find()){
			 System.out.println(mat.group(1));
			 System.out.println(mat.group(2));
			 uuid = mat.group(2);
		 }
		 //2.取得登录二维码
		 String url_login = url_login2weima.replace("{}", uuid);
		 System.out.println("login_url=>"+url_login);
		 String img_path = Utils.dowmImg(url_login);
		 System.out.println("img_path=>"+img_path);
		 //3.轮询手机端是否已经扫描二维码并确认在Web端登录
		 String login_url = check_login(uuid);
		 Map<String, String> cookies = Utils.getCookies(login_url);
		 System.out.println("cookies = "+cookies);
		 u.wxuin = cookies.get("wxuin");
		 u.wxsid = cookies.get("wxsid");
		 u.webwxuvid = cookies.get("webwxuvid");
		 u.deviceid = "e960817075982756";
		 
		 //4.调用初始化url
		 JSONObject post = new JSONObject();
		 JSONObject BaseRequest = new JSONObject();
		 post.put("BaseRequest", BaseRequest);
		 BaseRequest.put("Uin", u.wxuin);
		 BaseRequest.put("Sid", u.wxsid);
		 BaseRequest.put("Skey", "");
		 BaseRequest.put("DeviceID", u.deviceid);
		 String intUrl = url_init.replace("{t}", ""+System.currentTimeMillis());
		 res = Utils.postUrl(intUrl, post.toString());
		 JSONObject init =  JSONObject.parseObject(res);
		 JSONObject user  = init.getJSONObject("User");
		 System.out.println("欢迎您:"+user);
		 u.ujson = user;
		 u.name = user.getString("UserName");
		 u.nickName = user.getString("NickName");
		 JSONObject SyncKey = init.getJSONObject("SyncKey"); 
		 u.syncKey = getSyncKey(init);
		 u.SyncKey = SyncKey;
		 
		 u.SKey = init.getString("SKey");
		 u.connect = true;
		 
		 startSyncCheck();
		 
		 u.connect = false;
		//				 System.out.println(res);
				 
	}
	
	public void init() throws Exception{
		while(true){
			Thread t =  new Thread(){
				public void run(){
					try {
						WebWeixin.this.start();
					} catch (Exception e) {
						e.printStackTrace();
						u.connect = false;
					}
					synchronized (wait) {
						wait.notify();
					}
				}
			};
			t.start();
			Thread.sleep(300 * 1000);
			if(!u.connect){
				t.interrupt();
			}else{
				synchronized (wait) {
					wait.wait();
				}
			}
		}
	}
	
	//取得synckey
	public String getSyncKey(JSONObject json){
		JSONObject SyncKey = json.getJSONObject("SyncKey");
		 JSONArray Listarr = SyncKey.getJSONArray("List");
		 String synckey = "";
		 for(int i = 0;i<Listarr.size(); i++){
			 JSONObject jj = Listarr.getJSONObject(i);
			 synckey = synckey + jj.get("Key")+"_"+jj.get("Val")+"|"  ;
		 }
		 synckey = synckey.substring(0, synckey.length() - 2);
		 return synckey;
	}
	
	//check_login
	public String check_login(String uuid){
		String url_check = url_check_login.replace("{}", uuid);
		
		url_check = url_check.replace("{t}", ""+System.currentTimeMillis());
		int c = 0;
		String login_url = null;
		while(login_url == null){
			String res = Utils.getUrl(url_check);
			Pattern pat = Pattern.compile("window.redirect_uri=\"(.+)\";");  
			Matcher mat = pat.matcher(res);  
			if(mat.find()){
				System.out.println(mat.group(1));
				login_url = mat.group(1);
			}
			c++;
		}		
		System.out.println("经历了"+c+"次轮询");
		return login_url;
	}
	//循环检查新消息
	public void startSyncCheck(){ 
		while(true){
			String url = url_synccheck.replace("{0}", u.wxsid);
			url = url.replace("{1}", u.wxuin);
			url = url.replace("{2}", u.deviceid);
			url = url.replace("{3}", u.syncKey);
			url = url.replaceAll("[|]", "%7C");
			long t = System.currentTimeMillis();
			url = url.replace("{t}", ""+t);
			url = url.replace("{t}", ""+t);
			String res = Utils.getUrl(url);
			System.out.println("sync back="+res);
			Pattern pat = Pattern.compile("window.synccheck=\\{retcode:\"([0-9]+)\",selector:\"([0-9]+)\"}");  
			Matcher mat = pat.matcher(res);  
			if(mat.find()){
				int retcode = Integer.valueOf(mat.group(1));
				if(retcode != 0){
					System.out.println(url);
					System.out.println("退出登录"+res);
					break;
				}
				int count = Integer.valueOf(mat.group(2));
//				System.out.println(mat.group(2));		
				if(count > 0){
//					System.out.println("有"+count+"条新消息");
					
					String msgurl = url_msglist.replace("{}", u.wxsid);
					msgurl = msgurl.replace("{t}", ""+t);
					
					JSONObject post = new JSONObject();
					JSONObject BaseRequest = new JSONObject();
					BaseRequest.put("Uin", u.wxuin);
					BaseRequest.put("Sid", u.wxsid);
					post.put("BaseRequest", BaseRequest);
					post.put("SyncKey", u.SyncKey);
					post.put("rr", System.currentTimeMillis());
					
					res = Utils.postUrl(msgurl, post.toString());
					
//					System.out.println(res);
					
					JSONObject rj =   JSONObject.parseObject(res);
					u.SKey = rj.getString("SKey");
					if(u.SKey.equals("")){
						
						break;
					}
					JSONObject SyncKey = rj.getJSONObject("SyncKey"); 
					u.syncKey = getSyncKey(rj);
					u.SyncKey = SyncKey;
					
					
					JSONArray AddMsgList = rj.getJSONArray("AddMsgList");
					for(int i = 0;i<AddMsgList.size(); i ++ ){
						JSONObject msg = AddMsgList.getJSONObject(i);
						long msgid = msg.getLong("MsgId");
						String fname = msg.getString("FromUserName");
						String tname = msg.getString("ToUserName");
						String cont = msg.getString("Content");
						if(tname.equals(u.name)){
							System.out.println("新消息:"+fname+":"+cont);
//							sendMsg(fname, "1");
							//遍历
							for(WxMsgListener l : this.listeners){
								if(l.isEqualToMsg(fname, cont)){
									l.exec(fname, cont);
								}
							}
						}
					}
//					System.out.println(res);
				}
			}
		}
	}
	//发送消息
	public boolean sendMsg(String toname, String cont){
		String url = url_sendMsg.replace("{}", u.wxsid);
		url = url.replace("{t}", ""+ System.currentTimeMillis());
		JSONObject post = new JSONObject();
		JSONObject BaseRequest = new JSONObject();
		BaseRequest.put("Uin", u.wxuin);
		BaseRequest.put("Sid", u.wxsid);
		BaseRequest.put("DeviceID", u.deviceid);
		BaseRequest.put("Skey", u.SKey);
		post.put("BaseRequest", BaseRequest);
		JSONObject Msg = new JSONObject();
		Msg.put("ClientMsgId", System.currentTimeMillis());
		Msg.put("Content", cont);
		Msg.put("FromUserName", u.name);
		Msg.put("LocalID", System.currentTimeMillis());
		Msg.put("ToUserName", toname);
		Msg.put("Type",  1);
		post.put("Msg", Msg); 
		
		String res = Utils.postUrl(url, post.toString());
		if(res != null){
			JSONObject r =   JSONObject.parseObject(res);
			if(r.getJSONObject("BaseResponse").getInteger("Ret") == 0){
				System.out.println("发送成功");
				return true;
			}else{
				System.out.println("发送失败");
			}
		}else{
			//多次测试此时是发送成功的
		}
		System.out.println(res);
		return false;
	}
	
	/*************************                **************************************/
//	static HttpClientContext context = HttpClientContext.create();
//	//http get
//	public  static String get(String url){
//		try {
//			RequestConfig defaultRequestConfig = RequestConfig.custom()
//				    .setSocketTimeout(60000)
//				    .setConnectTimeout(60000)
//				    .setConnectionRequestTimeout(60000)
//				    .setStaleConnectionCheckEnabled(false)
//				    .setExpectContinueEnabled(false)
//				    .build();
//			CloseableHttpClient httpclient = HttpClients.custom()
//				    .setDefaultRequestConfig(defaultRequestConfig)
//				    .build();
//				
//			HttpGet httpget = new HttpGet(url);
//			CloseableHttpResponse response = httpclient.execute(httpget, context);
//			try {
////				System.out.println(response);
//				
//				return EntityUtils.toString(response.getEntity());
//			} finally {
//			    response.close();
//			}
//		} catch (ClientProtocolException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		return null;
//	}
//	//http getcookies
//	public  static Map<String, String> getCookies(String url){
//		try {
//			CloseableHttpClient httpclient = HttpClients.createDefault();
//			HttpGet httpget = new HttpGet(url);
//			CloseableHttpResponse response = httpclient.execute(httpget, context);
//			try {
//				System.out.println(response);
////				System.out.println(context.getCookieStore());
//				CookieStore cs = context.getCookieStore();
//				Map<String, String> map = new HashMap<String, String>();
//				for(Cookie c : cs.getCookies()){
//					map.put(c.getName(), c.getValue());
//				} 
//				return map;
//			} finally {
//			    response.close();
//			}
//		} catch (ClientProtocolException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		return null;
//	}
//	
//	//down img
//	public static String dowmImg(String url){
//		try {
//			CloseableHttpClient httpclient = HttpClients.createDefault();
//			HttpGet httpget = new HttpGet(url);
//			CloseableHttpResponse response = httpclient.execute(httpget, context);
//			try {
////				System.out.println(response);
//				byte [] bs = EntityUtils.toByteArray(response.getEntity());
//				File f =new File("img.png");
//				OutputStream os = new FileOutputStream(f);
//				os.write(bs);
//				os.close();
////				return EntityUtils.toString(response.getEntity());
//				return f.getAbsolutePath();
//			} finally {
//			    response.close();
//			}
//		} catch (ClientProtocolException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		return null;
//	}
//	//http post
//	public static String post(String url, Object ... kvs){
//		try {
//			List<NameValuePair> formparams = new ArrayList<NameValuePair>();
//			for(int i = 0;i < kvs.length/2; i++){
//				formparams.add(new BasicNameValuePair(""+kvs[2*i], ""+kvs[2*i + 1]));
//			}
//			UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
//			HttpPost post = new HttpPost(url);
//			post.setEntity(entity);
//			
//			CloseableHttpClient httpclient = HttpClients.createDefault();
//			CloseableHttpResponse response = httpclient.execute(post, context);
//			try {
////				System.out.println(response);
//				return EntityUtils.toString(response.getEntity());
//			} finally {
//			    response.close();
//			}
//		} catch (ClientProtocolException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		return null;
//	}
//	
//	//http post
//		public static String postString(String url, String str){
//			try {
//				StringEntity sentity = new StringEntity(str, Consts.UTF_8);
//				HttpPost post = new HttpPost(url);
//				post.setEntity(sentity);
//				
//				CloseableHttpClient httpclient = HttpClients.createDefault();
//				CloseableHttpResponse response = httpclient.execute(post, context);
//				try {
////					System.out.println(response);
//					HttpEntity ent = response.getEntity();
//					String res = "";
//					try {
//						res = EntityUtils.toString(ent, Charset.forName("UTF-8"));
//					} catch (ParseException e) {
//						e.printStackTrace();
//						res = null;
//					}
//					return res;
//				} finally {
//				    response.close();
//				}
//			} catch (ClientProtocolException e) {
//				e.printStackTrace();
//			} catch (IOException e) {
//				e.printStackTrace();
//			}
//			return null;
//		}
}

猜你喜欢

转载自hfutfei.iteye.com/blog/2025145
今日推荐