引子
关于企业微信PC版应用跳转到默认浏览器,我之前写过一篇文章:企业微信PC版应用跳转到默认浏览器,避坑指南,欢迎补充。。。
以前的文章里用的前后端一体的Jsp项目,这次我使用的是前后端分离的Vue项目,这两者实现的方式差异较大,我在开发的过程中也碰到了不少问题,所以我再写一篇文章作为补充。
官方文档推荐是使用最新的WECOM-JSSDK,我刚开始也是用WECOM-JSSDK,但是碰到莫名其妙的问题,无法实现跳转(文章中有说明),最后不了了之。
后来我就采用了JS-SDK,最后成功实现跳转功能。
使用JS-SDK的前提是通过config接口注入权限验证配置。
然后调用openDefaultBrowser方法打开默认浏览器。
具体请查看企微微信客户端API文档。
实现思路
由于Vue项目采用前后端分离架构,客户端和服务器端通常部署在不同的服务器上。在企业微信上跳转到默认浏览器的时候,如何把服务器的token传递到客户端浏览器是个难点。
我想出来的实现思路是这样的:
- 在跳转到默认浏览器之前,先通过企业微信的OAuth2方式,获取服务器端的登录token
- 在跳转的URL后面加上token参数,传递到用默认浏览器打开的项目页面(storeTonken.vue)中
- 在项目页面(storeTonken.vue)中提取URL中token,保存到Cookie中,然后跳转到项目首页,实现单点登录
整体的流程图如下:
操作步骤
引入JS文件
首先在vue项目中的index.html中引入JS文件。
<script src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
新建vue文件
然后在views文件夹下,新建一个文件夹“openDefaultBrowser”(名字任意取),然后新建一个index.vue和storeTonken.vue文件。
index.vue页面是跳转到默认浏览器用的,storeTonken.vue文件是保存token并跳转到首页用的。
配置白名单
然后在router中把这两个路径加入到白名单中,不用登录也能访问:
我这个项目还需要在permission.js中添加入白名单:
每个项目的架构不一样,请你根据实际情况配置。
需要注意的问题
设置可信域名
如应用页面需使用微信JS-SDK、跳转小程序等, 需完成域名归属验证。
就是在你的域名后面加上企业微信提供的这个 WW_verify***yo0iITyAeb6.txt 文件的URL,能够直接访问txt文件里面的内容。
如果你的域名是 abc.com,在浏览器中输入 http://abc.com/WW_verify***yo0iITyAeb6.txt,确保可以显示txt里面的内容。
那如何在服务器上设置呢?
我以nginx为例说一下步骤:
1、下载WW_verify***yo0iITyAeb6.txt 文件
2、把txt文件复制到服务器上,比如目录:/usr/local/etc 下
3、 在nginx.conf文件中添加 location = /WW_verify_Pmj1eyo0iITyAeb6.txt,记得把/usr/local/etc改成你自己的路径。
location = /WW_verify***yo0iITyAeb6.txt {
alias /usr/local/etc/WW_verify***yo0iITyAeb6.txt;
try_files $uri =404;
}
4、重启nginx
最后我们来看下效果:
然后,点击验证,就可以验证通过了:
设置企业可信IP
记得要设置企业可信IP,不然会报:not allow to access from your ip 的错误。
Connection reset 问题
我把项目发布到正式服务器后,结果后台报 Connection reset 的异常:
这个应该是网络连接的问题,我在服务器上运行:curl https://qyapi.weixin.qq.com
果然报错了:
看来真的是网络问题。
后来发现是服务器的外网权限没开~
WECOM-JSSDK 报错:not be accessed on strict mode
我在使用WECOM-JSSDK的时候,前端会报错:not be accessed on strict mode,这个问题,后来一直没有解决。
不知道是不是这个错误导致浏览器跳转失败。
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
at Arguments.invokeGetter (<anonymous>:3:28)
at Object._getConfigSignature (http://localhost:9528/afterSale/app.js:24558:11)
at Object.getConfigSignature (http://localhost:9528/afterSale/app.js:24538:38)
at http://localhost:9528/afterSale/app.js:2714:49
at step (http://localhost:9528/afterSale/app.js:2133:23)
at Object.next (http://localhost:9528/afterSale/app.js:2074:20)
at asyncGeneratorStep (http://localhost:9528/afterSale/app.js:2046:28)
at _next (http://localhost:9528/afterSale/app.js:2061:17)
at http://localhost:9528/afterSale/app.js:2066:13
at new Promise (<anonymous>)
openDefaultBrowser\index.vue 使用WECOM-JSSDK的代码的版本:
<template>
<div>
正在跳转到默认浏览器...
</div>
</template>
<script>
import { getWeiXinPermissionsValidationConfig } from '@/api/openDefaultBrowser'
import * as ww from '@wecom/jssdk'
export default {
data() {
return {
paramObject: {
url: '',
type: ''
}
}
},
created() {
this.getConfig()
},
methods: {
// 获取相关验证配置信息
getConfig() {
// 该paramUrl 为你使用微信sdk-js相关接口的页面地址 该地址需要配置到应用后台的可信域名下
const paramUrl = window.location.href.split('#')[0]
this.paramObject.url = paramUrl
this.companyConfigInit()
},
// 企业验证配置
companyConfigInit() {
const that = this
getWeiXinPermissionsValidationConfig(that.paramObject).then(response => {
ww.register({
appId: response.data.corpid, // 必填,企业微信的corpID
agentId: response.data.agentid, // 必填,当前应用的AgentID
jsApiList: ['openDefaultBrowser'], // 你要调用的sdk接口必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
getConfigSignature, // 必填,根据url生成企业签名的回调函数
getAgentConfigSignature // 必填,根据url生成应用签名的回调函数
})
async function getConfigSignature() {
console.log('calling getConfigSignature')
// 根据 url 生成应用签名,生成方法同上,但需要使用应用登录授权的 jsapi_ticket
return { timestamp: response.data.timestamp, nonceStr: response.data.nonceStr, signature: response.data.signature }
}
async function getAgentConfigSignature() {
console.log('calling getAgentConfigSignature')
return { timestamp: response.data.timestamp, nonceStr: response.data.nonceStr, signature: response.data.agentSignature }
}
ww.openDefaultBrowser({
// 在默认浏览器打开redirect_uri,并附加code参数;也可以直接指定要打开的url,此时不会附带上code参数。
url: 'https://work.weixin.qq.com/',
success(result) {
// 成功回调,result.errMsg 固定格式为“方法名:ok”
console.log('success:' + result)
},
fail(result) {
// 失败回调,通过 result.errMsg 查看失败详情
console.log('fail:' + result)
},
complete(result) {
// 完成回调,无论调用成功还是失败,都会回调该方法
console.log('complete:' + result)
}
})
})
}
}
}
</script>
后来实在解决不了,我就放弃使用WECOM-JSSDK了,转而使用JS-SDK,这段代码就算留个纪念吧。
如果你知道怎么解决,请得留言告诉我,谢谢。
项目代码
前端代码
openDefaultBrowser\index.vue
<template>
<div>
正在跳转到默认浏览器...
</div>
</template>
<script>
import { weiXinLogin, getWeiXinPermissionsValidationConfig } from '@/api/openDefaultBrowser'
import { setToken } from '@/utils/auth'
const wx = window.wx
export default {
data() {
return {
paramObject: {
url: ''
},
token: ''
}
},
created() {
// 微信登录
this.weiXinLogin()
},
methods: {
// 微信登录
weiXinLogin() {
const url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=***&redirect_uri=http%3A%2F%2Fabc.com%3A8890%2FweixinLogin&response_type=code&scope=snsapi_userinfo&agentid=***&state=STATE#wechat_redirect'
weiXinLogin(url).then(response => {
console.log(response)
this.token = response.data.token
setToken(response.data.token)
// 跳转到默认浏览器
this.getConfig()
})
},
// 获取相关验证配置信息
getConfig() {
// 该paramUrl 为你使用微信sdk-js相关接口的页面地址 该地址需要配置到应用后台的可信域名下
const paramUrl = window.location.href.split('#')[0]
this.paramObject.url = paramUrl
this.companyConfigInit()
},
// 企业验证配置
companyConfigInit() {
const that = this
getWeiXinPermissionsValidationConfig(that.paramObject).then(response => {
wx.config({
beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: response.data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
timestamp: response.data.timestamp, // 必填,生成签名的时间戳
nonceStr: response.data.nonceStr, // 必填,生成签名的随机串
signature: response.data.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: ['openDefaultBrowser'] // 必填,传入需要使用的接口名称
})
wx.ready(function() {
that.openDefaultBrowser()
})
wx.error(function(res) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
console.log(res)
})
})
},
openDefaultBrowser() {
const that = this
wx.invoke('openDefaultBrowser', {
// 在默认浏览器打开的uri,附加token参数
'url': 'http://abc.com:8889/***/#/storeTonken?token=' + that.token
}, function(res) {
console.log('res------------->', res)
if (res.err_msg !== 'openDefaultBrowser:ok') {
// 错误处理
}
})
}
}
}
</script>
以上代码中,通过 weiXinLogin 方法获取服务器的 token,先获取 token 然后再跳转到默认浏览器。
wx.config 中需要的参数通过 getWeiXinPermissionsValidationConfig 方法从服务器端获取,然后调用 openDefaultBrowser 方法实现默认浏览器跳转。
token通过url的参数传递:
'url': 'http://abc.com:8889/***/#/storeTonken?token=' + that.token
openDefaultBrowser.js
import request from '@/utils/request'
/**
* 微信登录
* @param {*} url
* @returns
*/
export function weiXinLogin(url) {
return request({
url: url,
method: 'get'
})
}
/**
* 获取配置信息
* @param {*} id
*/
export function getWeiXinPermissionsValidationConfig(params) {
return request({
url: `/getWeiXinPermissionsValidationConfig`,
method: 'get',
// 如果参数是个对象,不加{}
params: params
})
}
openDefaultBrowser\storeTonken.vue
<template>
<div />
</template>
<script>
export default {
created() {
// 获取URL中的token
const token = window.location.href.split('token=')[1]
this.$store.dispatch('user/singleSignIn', token).then(() => {
// 跳转到首页
this.$router.push({ path: '/' })
})
}
}
</script>
this.$store.dispatch(‘user/singleSignIn’, token) 是调用 Vuex 中的 actions,相关代码如下:
const actions = {
// 省略其他代码
// 单点登录设置token
singleSignIn({ commit }, token) {
return new Promise(resolve => {
commit('SET_TOKEN', token)
setToken(token)
resolve()
})
}
}
后端代码
WeiXinController
package com.zhanyd.app.controller;
import com.alibaba.fastjson.JSONObject;
import com.zhanyd.app.common.ApiResult;
import com.zhanyd.app.common.util.HttpService;
import com.zhanyd.app.common.util.JwtUtils;
import com.zhanyd.app.common.util.StringHelp;
import com.zhanyd.app.common.weixin.WeixinHelper;
import com.zhanyd.app.service.UserLogService;
import com.zhanyd.app.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@EnableAutoConfiguration
public class WeiXinController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
UserService userInfoService;
@Autowired
UserLogService userLogService;
/**
* 企业微信域名校验
* @return
*/
@ResponseBody
@GetMapping(value = "/WW_ver*****TyAeb6.txt")
public String wxPrivateKey(){
return "Pm*****Aeb6";
}
/**
* 单点登录,获取config接口注入权限验证配置
* @param url
* @return
* @throws NoSuchAlgorithmException
*/
@ResponseBody
@GetMapping(value = "/getWeiXinPermissionsValidationConfig")
public ApiResult<Map<String, Object>> getWeiXinPermissionsValidationConfig(String url) throws NoSuchAlgorithmException {
logger.info("获取config信息");
ApiResult<Map<String, Object>> apiResult = new ApiResult<Map<String, Object>>();
Map<String, Object> resultMap = new HashMap<>(16);
// 获取jsapi_ticket
String ticket = WeixinHelper.getJsApiTicket(WeixinHelper.AFTER_SALE_PC_CORPSECRET, "");
//当前时间戳转成秒
long timestamp = System.currentTimeMillis() / 1000;
//随机字符串
String nonceStr = "Wm3W****cnW";
// 获取JS-SDK使用权限签名
String signature = WeixinHelper.getJSSDKSignature(ticket, nonceStr, timestamp, url);
resultMap.put("corpid", WeixinHelper.APP_ID);
resultMap.put("agentid", WeixinHelper.AFTER_SALE_PC_AGENT_ID);
resultMap.put("timestamp", timestamp);
resultMap.put("nonceStr", nonceStr);
resultMap.put("signature", signature);
logger.info("config resultMap = " + resultMap);
return apiResult.success(resultMap);
}
/**
* 企业微信登录
* @return
*/
@ResponseBody
@GetMapping(value = "/weixinLogin")
public ApiResult<Map<String, Object>> weixinLogin(String code,HttpServletRequest request){
ApiResult<Map<String, Object>> apiResult = new ApiResult<>();
Map<String, Object> resultMap = new HashMap(16);
logger.info("微信登录:");
logger.info("code = " + code);
//获取tonken
String getTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + WeixinHelper.APP_ID + "&corpsecret=" + WeixinHelper.AFTER_SALE_PC_CORPSECRET;
String tokenContent = HttpService.post(getTokenUrl);
logger.info("tokenContent = " + tokenContent);
JSONObject jsonObject = JSONObject.parseObject(tokenContent);
String accessToken = jsonObject.getString("access_token");
logger.info("accessToken = " + accessToken);
//获取用户信息
String getUserUrl = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=" + accessToken + "&code=" + code;
String userContent = HttpService.post(getUserUrl);
logger.info("userContent = " + userContent);
jsonObject = JSONObject.parseObject(userContent);
String userId = jsonObject.getString("UserId");
logger.info("userId = " + userId);
if(!StringHelp.isEmpty(userId)){
// 登录逻辑,自行实现
logger.info("{} 登录成功", StringHelp.valueOf(user.get("userName")));
resultMap.put("userInfo", user);
resultMap.put("token", token);
logger.info("userInfo = " + user);
logger.info("token = " + token);
return apiResult.success(resultMap);
}
logger.info("{} 登录失败", userId);
}
}
WeixinHelper
package com.zhanyd.app.common.weixin;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhanyd.app.common.util.HttpService;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
public class WeixinHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(WeixinHelper.class);
// 企业id
public static final String APP_ID = "****";
// 售后平台应用
public static final String AFTER_SALE_PC_AGENT_ID = "****";
public static final String AFTER_SALE_PC_CORPSECRET = "****";
/**
* 存放ticket的容器
*/
private static Map<String, Ticket> ticketMap = new HashMap<>();
/**
* 获取token
* @return
*/
public static String getAccessToken(String secret) {
//获取token
String getTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + WeixinHelper.APP_ID + "&corpsecret=" + secret;
String tokenContent = HttpService.get(getTokenUrl);
LOGGER.info("tokenContent = " + tokenContent);
JSONObject jsonObject = JSONObject.parseObject(tokenContent);
String accessToken = jsonObject.getString("access_token");
LOGGER.info("accessToken = " + accessToken);
return accessToken;
}
/**
* 获取jsapi_ticket
* @param secret
* @param type
* @return
*/
public static String getJsApiTicket(String secret, String type) {
String accessToken = getAccessToken(secret);
String key = accessToken;
if (!StringUtils.isEmpty(accessToken)) {
if ("agent_config".equals(type)){
key = type + "_" + accessToken;
}
Ticket ticket = ticketMap.get(key);
if (!ObjectUtils.isEmpty(ticket)) {
long now = Calendar.getInstance().getTime().getTime();
Long expiresIn = ticket.getExpiresIn();
//有效期内的ticket 直接返回
if (expiresIn - now > 0) {
return ticket.getTicket();
}
}
ticket = getJsApiTicketFromWeChatPlatform(accessToken, type);
if (ticket != null) {
ticketMap.put(key, ticket);
return ticket.getTicket();
}
}
return null;
}
/**
* 获取企业的jsapi_ticket或应用的jsapi_ticket
* @param accessToken
* @param type 为agent_config时获取应用的jsapi_ticket,否则获取企业的jsapi_ticket
* @return
*/
public static Ticket getJsApiTicketFromWeChatPlatform(String accessToken, String type) {
String url;
if ("agent_config".equals(type)) {
url = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=" + accessToken+ "&type=" + type;
} else {
url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=" + accessToken;
}
Long now = System.currentTimeMillis();
if (!StringUtils.isEmpty(accessToken)) {
String body = HttpService.get(url);
LOGGER.info("ticketContent = " + body);
if (!StringUtils.isEmpty(body)) {
JSONObject object = JSON.parseObject(body);
if (object.getIntValue("errcode") == 0) {
Ticket ticket = new Ticket();
ticket.setTicket(object.getString("ticket"));
ticket.setExpiresIn(now + object.getLongValue("expires_in") * 1000);
return ticket;
}
}
}
return null;
}
/**
* 获取JS-SDK使用权限签名
* @param ticket
* @param nonceStr
* @param timestamp
* @param url
* @return
* @throws NoSuchAlgorithmException
*/
public static String getJSSDKSignature(String ticket, String nonceStr, long timestamp, String url) throws NoSuchAlgorithmException{
String unEncryptStr = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url;
MessageDigest sha = MessageDigest.getInstance("SHA");
// 调用digest方法,进行加密操作
byte[] cipherBytes = sha.digest(unEncryptStr.getBytes());
String encryptStr = Hex.encodeHexString(cipherBytes);
return encryptStr;
}
}
Ticket
package com.zhanyd.app.common.weixin;
/**
* @author zhanyd
* @date 2022-07-18
*/
public class Ticket {
private String ticket;
private Long expiresIn;
public Ticket() {
}
public Ticket(String ticket, Long expiresIn) {
this.ticket = ticket;
this.expiresIn = expiresIn;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public Long getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(Long expiresIn) {
this.expiresIn = expiresIn;
}
}
HttpService
package com.zhanyd.app.common.util;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpService {
private static int readTimeout=25000;
private static int connectTimeout=25000;
private static final Logger LOGGER = LoggerFactory.getLogger(HttpService.class);
/**
* POST方法
* @param sendUrl
* @param sendParam
* @return
*/
public static String post(String sendUrl, String sendParam) {
StringBuffer receive = new StringBuffer();
BufferedWriter dos = null;
BufferedReader rd = null;
HttpURLConnection URLConn = null;
LOGGER.info("sendUrl = " + sendUrl + " sendParam = " + sendParam);
try {
URL url = new URL(sendUrl);
URLConn = (HttpURLConnection) url.openConnection();
URLConn.setReadTimeout(readTimeout);
URLConn.setConnectTimeout(connectTimeout);
URLConn.setDoOutput(true);
URLConn.setDoInput(true);
URLConn.setRequestMethod("POST");
URLConn.setUseCaches(false);
URLConn.setAllowUserInteraction(true);
URLConn.setInstanceFollowRedirects(true);
URLConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
if (sendParam!=null && sendParam.length()>0) {
URLConn.setRequestProperty("Content-Length", String.valueOf(sendParam.getBytes().length));
dos = new BufferedWriter(new OutputStreamWriter(URLConn.getOutputStream(), "UTF-8"));
dos.write(sendParam);
dos.flush();
}
rd = new BufferedReader(new InputStreamReader(URLConn.getInputStream(), "UTF-8"));
String line;
while ((line = rd.readLine()) != null) {
receive.append(line);
}
} catch (java.io.IOException e) {
receive.append("访问产生了异常-->").append(e.getMessage());
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (rd != null) {
try {
rd.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
URLConn.disconnect();
}
String content = receive.toString();
LOGGER.info("content = "+content);
return content;
}
public static String post(String sendUrl, String sendParam,String ContentType) {
StringBuffer receive = new StringBuffer();
BufferedWriter dos = null;
BufferedReader rd = null;
HttpURLConnection URLConn = null;
LOGGER.info("sendUrl = " + sendUrl + " sendParam = " + sendParam);
try {
URL url = new URL(sendUrl);
URLConn = (HttpURLConnection) url.openConnection();
URLConn.setReadTimeout(readTimeout);
URLConn.setConnectTimeout(connectTimeout);
URLConn.setDoOutput(true);
URLConn.setDoInput(true);
URLConn.setRequestMethod("POST");
URLConn.setUseCaches(false);
URLConn.setAllowUserInteraction(true);
URLConn.setInstanceFollowRedirects(true);
URLConn.setRequestProperty("Content-Type", ContentType);
if (sendParam!=null && sendParam.length()>0) {
URLConn.setRequestProperty("Content-Length", String.valueOf(sendParam.getBytes().length));
dos = new BufferedWriter(new OutputStreamWriter(URLConn.getOutputStream(), "UTF-8"));
dos.write(sendParam);
dos.flush();
}
rd = new BufferedReader(new InputStreamReader(URLConn.getInputStream(), "UTF-8"));
String line;
while ((line = rd.readLine()) != null) {
receive.append(line);
}
} catch (java.io.IOException e) {
receive.append("访问产生了异常-->").append(e.getMessage());
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (rd != null) {
try {
rd.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
URLConn.disconnect();
}
String content = receive.toString();
LOGGER.info("content = "+content);
return content;
}
public static String get(String sendUrl) {
StringBuffer receive = new StringBuffer();
HttpURLConnection URLConn = null;
BufferedReader in = null;
try {
URL url = new URL(sendUrl);
URLConn = (HttpURLConnection) url.openConnection();
URLConn.setDoInput(true);
URLConn.connect();
in = new BufferedReader(new InputStreamReader(URLConn.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
receive.append(line);
}
} catch (IOException e) {
receive.append("访问产生了异常-->").append(e.getMessage());
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (java.io.IOException ex) {
ex.printStackTrace();
}
in = null;
}
URLConn.disconnect();
}
return receive.toString();
}
public static String post(String sendUrl) {
return post(sendUrl, null);
}
}
最后
最后我想说,我们在做项目的过程中肯定会碰到不少问题,碰到问题不要怕,遇到问题,我们就解决问题。
其实,带着问题去学习是一种很高效的学习方式,比如说Vuex,我以前也看过文档,但是一直看不太懂,始终一知半解,直到这次手动设置token Cookie的时候一直无法实现自动登录,原来项目中用了Vuex,要用Vuex的方式去设置。
借此机会,我又重新学了一遍Vuex文档,带着问题去学,答案都在文档里找到了,这样的学习效果就好很多了。
所以,遇到问题的时候,是我们学习的最佳时机,不要浪费任何一个问题。