浏览器下载文件时一共发送2次请求,如何把“下载次数”只记录为1次?

最近,个人官网实现了PDF下载功能,出于统计的考虑,增加了“下载次数”download_count这个字段。

但是,我今天突然发现,每次下载download_count都直接+2了。如果服务器发生这种事,还有一定的可能,本地就我一个人下载,怎么可能下载2次。于是,打开了log4j的debug模式,果然执行了2次更新请求。

@RequestMapping(value = "/download/pdf")

public void downloadPdf(@RequestParam Integer id, HttpServletRequest req,

HttpServletResponse res) {

Map<String, Object> article = articleService.get(id);

PdfDownload.doDownloadPdfPostWithShuiyin(req, res, article);
                articleService.plusDownloadCount(id);
    }

于是,想通过ThreadLocal<Integer> local;这种方式去记录,如果local中有值,表明当前线程已经下载过了,不需要再次更新下载次数。

但事实证明,上述做法不正确,实际现象是次数增加不够“稳定”,有时+1,有时+2。

后来,我又把local中的值,存放ip,判断是否为null,或者2次请求ip是否相同,结果仍然不够“稳定”。
--------------------------------------------------------
在实践过程中,我的一些“误解”:
1.下载文件,浏览器只会发送1次请求。实际是2次,毫无疑问。
2.发送2次请求,是同一个线程响应。我想当然的认为这2次请求,都是服务于“同一次下载”。
  事实证明,我太天真。
3.由于觉得这2次请求,我认为使用ThreadLocal存放个值,表明当前线程已经下载过了。
  事实证明,这不科学。2次请求,2个不同的线程响应。
4.“2次请求,2个不同的线程响应。”理论上是这样。
   但我们Team在做公司项目的时候,遇到了类似的问题。Boss后来想起来,Tomcat的线程是用“线程池” 实现的。
   多次请求可能是同一个线程处理,也可能是多个。 
  这一点,和实际发生的“更新次数不稳定” 非常吻合。
5.下载文章A,次数更新。下载文章B、C、D,次数都不再更新。
  这个不符合我的设想,原因是:下载没有比较文章的ID,不同文章的下载次数应该是相互独立的。

--------------------------------------------------------
现在有2个问题:
1.我就想实现自己最初的想法。
   浏览器发送2次请求,下载次数更新了2次。能不能只让它更新一次了,从而准确地体现下载次数!!!
  这个我目前还没有想到好的方法。

2. 改变需求,一个用户在一定时期内,下载一篇文章,无论多少次,都只算一次。
  下载不同的文章,次数应该且只应该增加1次。

我的想法:
  建立一个存放已经下载的队列,用户的ip和文章的id共同作为key。
  用户下载一次,就把用户IP和文章ID 共同组成的key,存放到队列里。
  当来了新的下载请求时,从队列中查找,是否已经存在key,如果不存在,才+1.否则,不更新次数。

原文首发:http://fansunion.cn/article/detail/141.html

时间: 2024-12-25 20:41:42

浏览器下载文件时一共发送2次请求,如何把“下载次数”只记录为1次?的相关文章

【转】正确处理浏览器在下载文件时HTTP头的编码问题(Content-Disposition)

最近在做项目时遇到了一个 case :需要实现一个强制在浏览器中的下载功能(即强制让浏览器弹出下载对话框),并且文件名必须保持和用户之前上传时相同(可能包含非 ASCII 字符). 前一个需求很容易实现:使用 HTTP Header 的 Content-Disposition: attachment 即可,还可以配合 Content-Type: application/octet-stream 来确保万无一失.而后一个需求就比较蛋疼了,牵扯到 Header 的编码问题(文件名是作为 filena

正确处理下载文件时HTTP头的编码问题(Content-Disposition)

转自:https://blog.robotshell.org/2012/deal-with-http-header-encoding-for-file-download/ 最近在做项目时遇到了一个 case :需要实现一个强制下载功能(即强制弹出下载对话框,阻止浏览器尝试解析显示某些文件格式),并且文件名必须保持和用户之前上传时相同(可能包含非 ASCII 字符). 前一个需求很容易实现:使用 HTTP Header 的 Content-Disposition: attachment 即可,还可

[ASP.NET][C#]下载文件时中文文件名出现乱码

负责的网站在ASP.NET网页有一段下载Word/Excel文件的程序,最近使用者要求的文件名称内含繁体中文字, 同事用chrome/firefox浏览器测试下载都很正常显示,但用IE(版本11)开启时,却出现了乱码. 1.准备一个中文文件名的文件 ASP.NET MVC 2.在HomeControler中加入下载程序Download public ActionResult Download() { //文件位置 string filepath = @"E:testWebApplication1

实现在 .net 中使用 HttpClient 下载文件时显示进度

原文:实现在 .net 中使用 HttpClient 下载文件时显示进度 在 .net framework 中,要实现下载文件并显示进度的话,最简单的做法是使用 WebClient 类.订阅 DownloadProgressChanged 事件就行了. 但是很可惜,WebClient 并不包含在 .net standard 当中.在 .net standard 中,要进行 http 网络请求,我们用得更多的是 HttpClient.另外还要注意的是,UWP 中也有一个 HttpClient,虽然

下载文件时遮罩层示例。

新需求是在原来的代码上进行优化查询. 优化完成之后导出功能还是需要1~3秒响应时间,毕竟数据量大,业务逻辑也较为复杂. 为了避免用户重复点击“导出”按钮,故写个遮罩层来示意用户当前正在发送下载的请求. 点击导出或下载按钮弹出遮罩层,由于无法判断文件什么时候在后台读取完,遮罩层什么时候消失成了关键. 思路是这样的: 在请求到后台下载的Servlet时,往Session中setAttribute一个值. 前台页面写个定时器,不断请求另外一个Servlet获取Session中set的值,当值为空字符串

基于Android 下载文件时,更新UI简单帮助类

由于在项目开发时,有这样的简单需求,问谷歌,网络上也有好多Utils工具类,但是比较冗余.自己就简单的写了一个简单帮助类. /** * 下载文件,更新UI简单帮助类 * * @author jarlen * */ public class DownLoadHelper { private static final int DOWN_BEGIN = 0; private static final int DOWN_UPDATA = 1; private static final int DOWN_

Servlet:浏览器下载文件时文件名为乱码问题

1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 String filename = request.getParameter("filename"); 3 System.out.println(filename); 4 String path = getServletContext().get

下载文件时出错,chrome 浏览器显示来自服务器的响应包含重复标头

现象: Chrom浏览器报错: 来自服务器的响应包含重复标头.此问题通常是由于网站或代理配置不正确导致的.只有网站或代理管理员才能解决此问题. Firfox和IE都能正常运行 可能出现的原因: 文件名中包含特殊字符或","之类的符号. 解决方案: 原来代码 response.setHeader("Content-disposition", "attachment;filename="+fileName); 修改后代码 response.setHe

解决下载文件时,多种浏览器下中文乱码问题

<?php $ua = $_SERVER["HTTP_USER_AGENT"]; $filename = "中文 文件名.txt"; $encoded_filename = urlencode($filename); $encoded_filename = str_replace("+", "%20", $encoded_filename); header('Content-Type: application/octet