最近在做一个微信网页版的小游戏,在获取用户数据的时候遇到了跨域的问题。
首先说明一下微信网页授权的机制,你的网页授权入口应该是类 似“https://open.weixin.qq.com/connect/oauth2/authorize? appid=wxbdeafce2a5d59561&redirect_uri=https%3a%2f%2fsaima.bidongtu.cn%2frenzheng&response_type=co de&scope=snsapi_userinfo&state=123#wechat_redirect”的地址,其中redirect_uri后面应该为你后台的解密的接口口地址。当你请求这个地址时,会先向微信服务器请求授权并获取code,获取code成功后在根据redirect_uri路径去请求你的后台服务器,后台服务器根据code去微信服务器获取用户的信息然后返回给前端页面。
可是在实际开发过程中遇到了跨域的问题,我最开始是这样想的,首先写一个页面,在这个页面加载的时候发送“https://open.weixin.qq.com/connect/oauth2/authorize? appid=wxbdeafce2a5d59561&redirect_uri=https%3a%2f%2fsaima.bidongtu.cn%2frenzheng&response_type=co de&scope=snsapi_userinfo&state=123#wechat_redirect”的ajax请求,获取用户的信息,(/renzheng为后台解密借口地址)。可是这样做后台能获取到用户信息,但是不能讲信息传送给前端页面,因为存在跨域问题。后来咨询了一下朋友,得到这样一个解决方案。
首先在redirect_uri路径里面直接请求静态页面,也就是这样“https://open.weixin.qq.com/connect/oauth2/authorize? appid=wxbdeafce2a5d59561&redirect_uri=https%3a%2f%2fsaima.bidongtu.cn%2findex.html&response_type=co de&scope=snsapi_userinfo&state=123#wechat_redirect”的地址,微信服务器会获取code然后去访问你的后端服务器获取index.html静态页面返回给前端。此时在前端页面里面可以从当前的地址信息里面获取code,然后直接向你的后端服务器解密端口发送请求,此时就不存在跨域问题。具体代码如下:
在index.html页面解析地址获取code代码:
function getopenId() {
var userData = null;
userData = JSON.parse(localStorage.getItem('user'));
if(userData) {
return userData;
} else {
var getQueryString = function(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if(r != null) return unescape(r[2]);
return null;
};
var code = getQueryString('code');
if(code) {
$.ajax({
type: "get",
url: "https://saima.bidongtu.cn/renzheng.do",
data: {
code: code
},
async: false,
success: function(d) {
console.log(d)
userData = d;
},
error: function(data) {
alert('网络错误');
}
});
} else {
alert('请从微信公众号打开');
}
localStorage.setItem('user', JSON.stringify(userData));
return userData;
}
后端的解密授权接口如下:
@RequestMapping("/renzheng.do")
@ResponseBody
public Object authMehtod(String code){
System.out.println("code:"+code);
String jsonText ="";
StringBuffer url=new StringBuffer("https://api.weixin.qq.com/sns/oauth2/access_token?");
url.append("appid=").append("wxbdeafce2a5d59561").append("&");
url.append("secret=").append("ba37510578b839ca754e18f41cee4518").append("&");
url.append("code=").append(code).append("&");
url.append("grant_type=").append("authorization_code");
System.out.println("url:"+url);
jsonText= Tools.getStaticString(url.toString());
System.out.println("jsonText:"+jsonText);
WeixinBackInfo weixinBackInfo =null;
try {
weixinBackInfo = mapper.readValue(jsonText, WeixinBackInfo.class);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Map<String,String> map=new HashMap<>();
map.put("error","解密失败");
return map;
}
System.out.println("openId:"+weixinBackInfo.getOpenid());
UserInfo userInfo = new UserInfo();
if(weixinBackInfo.getErrcode()==null){
try {
userInfo=getUserInfo(weixinBackInfo);
} catch (Exception e) {
e.printStackTrace();
Map<String,String> map=new HashMap<>();
map.put("error","解密失败");
return map;
}
}
if(userInfo.getOpenid()!=null){
UserDTO userDTO=userService.findUser(userInfo.getOpenid());
if(userDTO==null){//如果数据库没有此人信息,将此人存入数据库
userService.addUser(userInfo.getOpenid(),userInfo.getHeadimgurl());
}
}
return userInfo;
}
public UserInfo getUserInfo(WeixinBackInfo backInfo) throws Exception {
StringBuffer url = new StringBuffer("https://api.weixin.qq.com/sns/userinfo?");
String jsonText ="";
url.append("access_token=").append(backInfo.getAccess_token()).append("&");
url.append("openid=").append(backInfo.getOpenid()).append("&");
url.append("lang=en");
System.out.println("UserInfo_Url:"+url);
jsonText=Tools.getStaticString(url.toString());
String str="";
str=new String(jsonText.getBytes("ISO-8859-1"),"UTF-8");
System.out.println("UserInfo_Url:"+str);
UserInfo userInfo =null;
userInfo = mapper.readValue(str, UserInfo.class);
return userInfo;
}
所用到的实体类以及工具:
用户类UserInfo:
public class UserInfo {
private String language;
private String openid;
private String nickname;
private String sex;
private String province;
private String city;
private String country;
private String headimgurl;
private List<String> privilege;
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getHeadimgurl() {
return headimgurl;
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public List<String> getPrivilege() {
return privilege;
}
public void setPrivilege(List<String> privilege) {
this.privilege = privilege;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
private String unionid;
}
微信服务器返回的JSON解析后的实体类WeixinBackInfo
public class WeixinBackInfo {
private String access_token;
private String expires_in;
private String refresh_token;
private String openid;
private String scope;
private String errcode;
private String errmsg;
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expires_in) {
this.expires_in = expires_in;
}
public String getRefresh_token() {
return refresh_token;
}
public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getErrcode() {
return errcode;
}
public void setErrcode(String errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
}
java后台向微信服务器发送请求的工具类Tools
public class Tools {
private static HttpClient client;
private static GetMethod getMethod;
static {
client = new HttpClient();
}
public static String getStaticString(String URL){
getMethod = new GetMethod(URL);
String jsonText="";
try {
int status = client.executeMethod(getMethod);
if (status == HttpStatus.SC_OK) {// HTTP 200 OK
jsonText = getMethod.getResponseBodyAsString();
}
} catch (Exception e) {
System.err.println(e);
}
return jsonText;
}
}
该工具类需要用到commons-httpclient包,请导入依赖
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
如上就能解决用ajax获取用户信息时的跨域问题了