微信开发页面请求重发问题
来源:互联网 发布:百世快递软件 编辑:程序博客网 时间:2024/06/05 14:13
偶然的一次因为项目再生产上出了问题发现的
对于微信浏览器(安卓版本)如果页面请求结束等待响应时间超过10S微信浏览器会认为没响应,并主动重发上条ajax请求。
对于这两条ajax请求,页面的处理是响应第二条响应,那么第一条响应去哪里呢?鬼知道,不过这里我要说的是我的解决方案:
针对这两条ajax的请求结束时,其实响应结果都会返回,只不过页面仅仅响应第二条结果,那么我们的做法应该是什么?
我的做法是当第一条响应回来的时候我将其存储起来,当第二条请求来临时,我们返回第一条的响应,这样响应的就是第一条结果。问题得到解决。
但是新的问题来了 我们应该如何判断这两次请求是同一条请求呢?这时我的做法是模仿防止表单重复提交的方式,
我会在请求页面设置一个隐藏属性,也就是token当然这个token要永远为唯一的,并且每次用户访问到这个页面的时候token的值都需要变化
如何定制token并不是这里要讲的,在此咱不说明,在我们使用ajax发起请求的时候我会将token一并传入后台,在后台首先校验token是否为唯一,
如果为唯一则说明是第一次请求,会按照正常的流程进行,并且储存token。
如果token的值不是唯一的,则说明该请求是重复发送,这时候我们需要去第一个token中将响应找回来,并响应给页面。
当然如果存储响应信息呢?我这里有几种方式可以存储:
1、将响应存储在服务器内存中,这种性能方面是最好的,但是数据容易丢失。
2、将响应存储在nosql中,这种是我最推崇的,数据安全方面,性能方面都很棒,但是由于我们的项目没有使用nosql,所以我没用使用该方式。(推荐)
3、将响应存储在文件中,由于我们项目使用的是webservice技术,所以我们存储在xml里面比较方便,除了xml我们还可以存储在json文件里,但是这里我选取的是properties文件,为什么选取它呢?因为他是以键值的形式存储的,我们将唯一的token进行处理之后生成唯一键,通过键来获得响应,这样的好处是响应文件会少,一个properties文件可以存储很多的响应,但是xml或者是json文件,一个文件仅可以存储一个响应,这就是我选取properties文件的原因。
4、将响应存储在数据库中,这种方式可行,但是效率最差,不推荐使用。
下面列一下代码:
生成properties文件:并返回该文件真实路径,方便程序读取。
我的做法是每天生成一个properties文件。按年/月/日.properties存储。
/** * * @param path properties根目录 * @return properties文件真实位置 * @throws IOException */private static String createFile(String path) throws IOException{Calendar cal = Calendar.getInstance();int getmonth = cal.get(Calendar.MONTH)+1;int getday= cal.get(Calendar.DATE); String year =String.valueOf(cal.get(Calendar.YEAR)); String month=""; String day=""; if(getmonth<=9){ month="0"+String.valueOf(getmonth); }else{ month=String.valueOf(getmonth); } if(getday<=9){ day="0"+ String.valueOf(getday); }else{ day=String.valueOf(getday); } path = path + "/" + year + "/" + month + "/" + day + ".properties";File file = new File(path);if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}if(!file.exists()){file.createNewFile();}return path;}
@RequestMapping(value = "/confirmUploadFile_jsonp.mm")public void confirmUploadFile_jsonp(HttpServletRequest request, HttpServletResponse response,String callback,String token) {Long begin = System.currentTimeMillis();String thirdUserId = (String) request.getSession().getAttribute(WXCst.THIRD_USER_TABLE_ID);Long userId = Long.parseLong(thirdUserId);logger.info("======token-------UUID为--------------------"+token+"=========");logger.info("======THIRD_USER_TABLE_ID为--------------------"+userId+"=========");SpMethodRecord record = spMethodRecordService.findMethodRecordByToken(token,userId);//通过token查询数据库是否有记录Message msg = null;boolean falg = true;//用于标识token是否唯一try {//将唯一token生成年/月/日.properties文件记录tokenString propertiesFile = createFile(PROPERTIES_FILE_PATH);//获取properties文件真实路径//当token为第一次产生的时候进行存储tokenif( null == record ){//进行数据库记录token方便日后查错String transNo = spInterfacePacketService.querySeq();SpMethodRecord spMethodRecord = new SpMethodRecord();spMethodRecord.setCreateTime(new Date());spMethodRecord.setIsDelete(0);spMethodRecord.setThirdUserId(userId);spMethodRecord.setToken(token);spMethodRecord.setTransno(transNo);spMethodRecord.setUpdateTime(new Date());spMethodRecordService.saveMethodRecord(spMethodRecord );//开始对properties文件进行操作Properties pps = new Properties();pps.load(new InputStreamReader(new FileInputStream(propertiesFile),"UTF-8"));//设定properties文件编码防止乱码产出Enumeration enum1 = pps.propertyNames();//得到配置文件的名字while(enum1.hasMoreElements()) { String strKey = (String) enum1.nextElement(); if( token.equals(strKey)){ falg = false; logger.info("这里token重复 值为====="+pps.getProperty(strKey)); }}msg = "响应结果";//这里隐藏项目业务流程(使用webservice技术返回的响应信息)String gsonMsg = GsonUtils.toGson(msg);//通过Google的Gson将对象转换成字符串进行存储if(falg){logger.info("这里token是唯一的 进行存值");pps.setProperty(token, gsonMsg);//将返回结果进行json处理存入properties文件PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(propertiesFile),"UTF-8")));pps.store(out, new Date()+"添加键"+token);out.flush();out.close();}else{logger.error("==================UUID生成token出现重复!!!!!!!!!!===================");} }else{logger.info("这里是读取重复值==============================================");//开始对properties文件进行操作Properties pps = new Properties();pps.load(new InputStreamReader(new FileInputStream(propertiesFile),"UTF-8"));//防止读取乱码String property = pps.getProperty(token);
//这里处理如果未保存响应时进行线程延时问题//这里是处理当第二次请求来临时,但是第一次的响应结果还没有返回的情况,其做法就是让当前线程睡眠一定时间再次读取,直至读取到,或者认为超时//我这里线程最大睡眠时间为15s,如果还没有响应就放弃了吧,这样也太慢了for(int i=0;i<=2;i++){if( null == property){logger.info("第"+i+"次读取重复值====值未取到====================================");Thread.currentThread().sleep(5*1000);}pps = new Properties();//这里一定要new 对象读取,否则会读不到,为啥你自己测试就知道原因了。pps.load(new InputStreamReader(new FileInputStream(propertiesFile),"UTF-8"));property = pps.getProperty(token);}if( null == property ){logger.error("==================将近20s未响应数据!!!!!!!===================");msg=new Message("201","网络请求异常。请联系系统管理员");}else{logger.info("读取重复值====值为=============="+property+"======================");msg = GsonUtils.fromGson(property, Message.class);}}} catch (Exception e) {logger.error("错误信息", e);}finally {logger.info("执行完成耗时:" + (System.currentTimeMillis() - begin) / 1000);}renderJsonp(response, msg, callback);}我们这里对页面响应的是jsonp类型的数据,封装成了一个方法,在此并不介绍。如果使用以上方式没有得到解决的,可以与我沟通。对于微信端10s重复请求,我测试发现其实际是换了一个线程,但是只重复发送一次。0 0
- 微信开发页面请求重发问题
- [JAVA]微信的请求重发解决办法
- IHS页面等待时间超过60秒,请求自动重发问题解决办法
- ajax请求不同页面的微信JSSDK的问题
- 微信开发https请求
- 初接触微信开发--页面跳转问题
- 开发页面在微信显示大小异常的问题
- 微信公众号开发---微信请求服务端取值问题
- bootstrap 微信开发页面
- 微信开发之发送get请求
- 后台收到微信重复请求问题
- 微信wap开发-页面自适应大小
- 微信wap开发---页面自适应大小
- 微信开发页面授权获取用户信息
- 微信开发-分享页面修改
- 微信公众号页面开发相关
- 微信自定义分享页面接口开发
- 解决前端开发之微信内置浏览器页面渲染和缓存问题
- python-3-如何快速找到多个字典中的公共键(key)?
- 使用Dlib库进行人脸检测,人脸对齐和人脸识别
- Student Attendance Record I
- 为什么很少见工资高的程序员炫富?
- 高德地图获取Key
- 微信开发页面请求重发问题
- 遍历json
- 获取非行间样式(封装)
- 无法访问服务器、访问服务器显示在建设中
- xgboost
- SpringMVC教程--异常处理器详解
- var result = eval("(" + data + ")"); 这个问题还没有解决 !!!!!!
- File工具类
- HTML5游戏开发的细节问题