微信开发页面请求重发问题

来源:互联网 发布:百世快递软件 编辑:程序博客网 时间: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
原创粉丝点击