5

所以我为测验做了一些计时器。问题是,我刚刚意识到,当我把

javascript: alert("blah");

在地址中,弹出警报框会暂停我的计时器。这在测验中是非常不需要的。

我认为没有任何方法可以阻止这种行为......但无论如何我都会问。

如果没有,介意建议我该怎么办?

4

8 回答 8

10

永远不要依赖 javascript(或任何其他客户端时间)来计算在回发或不同页面之间完成的操作所经过的时间。

如果你总是比较服务器日期,人们就很难作弊:

  1. 第一个页面请求,存储服务器时间
  2. 每 N 秒使用 javascript 调用一次,比较 2 个服务器时间,并返回经过的时间(仅用于显示)
  3. 当用户提交表单时,比较两个服务器时间,计算经过的时间,并丢弃那些耗时过长的(即:可能的作弊者)
于 2008-10-13T16:58:40.970 回答
6

显然预览渲染与发布的渲染不同。这一段是为了确保接下来的两行显示为代码。

// Preserve native alert() if you need it for something special
window.nativeAlert = window.alert;

window.alert = function(msg) {
    // Do something with msg here. I always write mine to console.log,
    // but then I have rarely found a use for a real modal dialog,
    // and most can be handled by the browser (like window.onbeforeunload).
};
于 2008-10-13T16:21:10.887 回答
5

不,没有办法阻止警报停止 JavaScript 中的单线程。可能您可以使用其他一些用户通知方式,例如浮动层。

于 2008-10-13T15:49:20.093 回答
3

它是模态的并停止执行。考虑一种不会像灯箱技术那样暂停执行的替代方案。

于 2008-10-13T15:51:49.153 回答
3

我认为提问者试图防止作弊。由于用户可以键入 javascript: alert("paused"); 进入地址栏,或者制作一个书签来做到这一点,很容易暂停测验和作弊。

我唯一能想到的是使用 Date() 来获取当前时间,并在计时器触发时再次检查它。然后,如果时间差没有合理地接近预期的计时器持续时间,请发出警告并取消该问题的答案或让他们不及格测验。没有办法阻止用户暂停您的测验,但应该可以抓住他们。

当然,通过任何防作弊功能,您都会激励人们成为更好的作弊者。一个人可以在他们的 PC 上更改系统时间,并欺骗从操作系统获取时间的 javascript Date() 构造函数。

您可以使用时间间隔对一秒的时间间隔长度进行重复的时钟比较。间隔处理程序还可以更新用户显示器上的剩余时间字段。然后,随着测验时间的流逝,用户可以感受到压力的增加。娱乐时间!

于 2008-10-13T16:25:02.660 回答
2

SyaZ 问题的反馈循环已经澄清了相关问题。

这是迄今为止总结好的答案的尝试:

  • 客户端脚本本质上很容易操纵以欺骗在线测验。查看@Filini 的服务器端方法

  • window.alert = function(msg) {} 将覆盖alert()并且可能会打败放入地址栏中的低悬果:javascript:alert('Pausing page so I can google answer') 或者我将使用我的电话-现在的朋友。 礼貌@eyelidlessness

  • 如果您必须使用客户端方法,而不是使用 setTimeOut(),您可以使用这样的自定义基于日期比较的暂停函数(@Mnebuerquo 的概念,我的代码示例(@micahwittman)):

例子:

var beginDate = new Date();

function myTimeout(milsecs){
  do { curDate = new Date(); }
    while((curDate-beginDate) < milsecs);
}

function putDownYourPencils(milsecs){
  myTimeout(milsecs);
  var seconds = milsecs / 1000;
  alert('Your '  + seconds + ' seconds are up. Quiz is over.');
}

putDownYourPencils(3000);
于 2008-10-13T20:28:25.583 回答
2

最终,您无法信任用户输入。如果不跟踪服务器上经过的时间,就不能保证数据没有被操纵。

但是,如果您确信您的测验者不精通 JavaScript,并且仅仅依靠他们在某处发现的“技巧”,您可以使用以下代码测试作弊(暂停),这不需要修改窗口警报:

var timer = {
    startDatetime: null,
    startSec: 0,
    variance: 1,
    exitOnPause: true,
    count: function (config) {
        var that = this;

        if (typeof config == "object" && typeof parseInt(config.seconds) == "number" && !isNaN(parseInt(config.seconds)))
        {
            if (typeof parseFloat(config.variance) == "number" && !isNaN(parseFloat(config.variance))) this.variance = config.variance;
            if (typeof config.exitOnPause == "boolean") this.exitOnPause = config.exitOnPause;

            if (config.seconds > 0)
            {
                if (!this.startSec) this.startSec = config.seconds;
                if (!this.startDatetime) this.startDatetime = new Date();
                var currentDatetime = new Date();

                if (currentDatetime.getTime() - this.startDatetime.getTime() > (this.startSec - config.seconds) * this.variance * 1000)
                {
                    if (typeof config.onPause == "function") config.onPause();

                    if (!this.exitOnPause)
                    {
                        this.startDatetime = new Date();
                        this.startSec = config.seconds--;
                        window.setTimeout(function () { that.count(config); }, 1000);
                    }
                }
                else
                {
                    config.seconds--;
                    window.setTimeout(function () { that.count(config); }, 1000);
                }
            }
            else
            {
                if (typeof config.onFinish == "function") config.onFinish();
            }
        }
    }
};

此计时器对象有一个方法 count(),它接受一个对象作为输入。它期望输入对象中至少有一个 seconds 属性。

出于某种原因,window.setTimeout 并不总是按预期工作。有时,在我的机器上,应该在 1 秒后执行代码的 window.setTimeout(x, 1000) 花费了 2 秒以上。因此,在这种情况下,您应该允许差异,这样没有作弊的人就不会被标记为作弊者。方差默认为 1,但可以在输入对象中覆盖。这是如何使用此代码的示例,它允许 2.5 秒的“摆动空间”用于慢戳:

timer.count({
    seconds: 10,
    onPause: function () { alert("You cheated!"); window.location.replace("cheatersAreBad.html"); },
    onFinish: function () { alert("Time's up!"); },
    variance: 2.5
});

例如,通过这样的解决方案,您可以使用 Ajax 告诉服务器端脚本用户已暂停计时器或将用户重定向到解释他们被抓到作弊的页面。如果出于某种原因,您希望允许用户在被发现作弊后继续参加测验,您可以将 exitOnPause 设置为 false:

timer.count({
    seconds: 10,
    exitOnPause: false,
    onPause: function () { recordCheaterViaAjax(); },
    onFinish: function () { alert("Time's up!"); },
    variance: 2.5
});
于 2008-10-13T22:57:06.970 回答
0

服务器会话可以设置为在 1 小时后到期。javascript 只能用作显示工具,让用户知道还剩多少时间。如果他决定通过暂停计时器来作弊,那么在发布他的测试时他可能会惊讶于他的会话已超时。

于 2012-06-26T18:16:03.907 回答