Jump to content

Prevenir efeitos colaterais do botão "Back" dos browsers


passarito

Recommended Posts

Bom dia,

Estou às voltas com o problema do botão "Back" dos browsers.

Quando os utilizadores carregam no botão "back" depois de terem inserido ou alterado um registo ele volta à página anterior e faz outro registo ou altera com dados de outro registo.

Estou a tentar descobrir um método que quando a página vai para trás, impeça de re-escerver na base de dados,

Já experimentei aplicar alguns métodos usando uma variável de controlo, mas sem sucesso. Também já pesquisei no Sr. Google mas sem sucesso.

Estou a usar Classic ASP / VBScript

Alguém tem sugestões para o caso.

Obrigado

Link to comment
Share on other sites

Podes usar um timestamp para controlar.
Quando sais da página através dos teus links/botões de ação (por exemplo botão de susbmit num form), metes o timestamp na sessão e passas o mesmo no URL.

Quando entras numa página verfificas se o timestamp do url é o mesmo que tens em sessão e:

  • se o timestamp é diferente, então o pedido da página é inválido
  • se o timestamp é igual, então a página é válida e atualiza o timestamp da sessão

Quando fazes back, o timestamp do url é diferente do timestamp que está em sessão, o que faz com que detetes que a página é inválida.

10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Link to comment
Share on other sites

Boas,

Encontrei os mesmos problemas dos meus testes anteriores. Sempre que o browser volta atrás ele re-atualiza os valores, O browser atualiza o valor da hora e depois quando faz a comparação é claro que não pára.

Tenho a atualização da variável de sessão a atualizar numa função em javascript no onclick do botão "ok" do formulário.

Dá-me ideia que vou ter aqui um problema jeitoso...

Link to comment
Share on other sites

Disclaimer: não tenho grande experiência de frontend 😄

Parece-me que aquilo que queres é de certo modo tornar o pedido (POST?) idempotente.  Existem várias soluções para fazer isso, sendo que a minha favorita (no contexto de serviços REST) é usar uma chave secundária definida pelo cliente, que armazenas também na BD, numa coluna única.  Em serviços REST a ideia é sobretudo permitir ao cliente repetir o pedido caso não obtenha resposta, pelo que o cliente só tem que gerar um valor aleatório (e.g. UUID) para este fim.  Mas por vezes o cliente até tem algum outro identificador que pode usar (quando o cliente é outro serviço).

No caso de websites, e assumindo que o pedido não é feito por Javascript, isto é um pouco mais complexo de implementar, mas diria que deve dar para fazê-lo com um cookie, que assumo que sejam incluídos em todos os pedidos ao servidor.

Link to comment
Share on other sites

18 hours ago, passarito said:

Boas,

Encontrei os mesmos problemas dos meus testes anteriores. Sempre que o browser volta atrás ele re-atualiza os valores, O browser atualiza o valor da hora e depois quando faz a comparação é claro que não pára.

Tenho a atualização da variável de sessão a atualizar numa função em javascript no onclick do botão "ok" do formulário.

Dá-me ideia que vou ter aqui um problema jeitoso...

Isso não está bem implementado.

O browser não tem de atualizar absolutamente nada, isso tem de ser tudo feito e controlado no lado do servidor.
Não é possível atualizar a variável de sessão numa função de Javascript no browser. O Javascript é uma linguagem client-side e a sessão é server-side.
Ou seja, o que quer que aches que estás a fazer não é o que devias estar a fazer.

Vê no manual da linguagem que estás a usar como usares a sessão.

 

10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Link to comment
Share on other sites

37 minutos atrás, M6 disse:

Isso não está bem implementado.

O browser não tem de atualizar absolutamente nada, isso tem de ser tudo feito e controlado no lado do servidor.
Não é possível atualizar a variável de sessão numa função de Javascript no browser. O Javascript é uma linguagem client-side e a sessão é server-side.
Ou seja, o que quer que aches que estás a fazer não é o que devias estar a fazer.

Vê no manual da linguagem que estás a usar como usares a sessão.

 

Se está bem implementado ou não, não sei. O que sei é que não está a fazer o que eu quero 😞

Neste momento estou em "Brain Storming", vou testando todas as soluções que me aparecem ser viaveis... depois penso na melhor implementação.

A opção do javascript na opção onclick do botão era para obter o timestamp no momento em que a pessoa clica e isso teria de ser feito em client-side pois o vbscript corre todo o código de uma vez só e o timestamp ficaria assim desatualizado.

Deixo aqui o código que estou a usar para fazer os testes.

<title>Anular Boto Back</title>

<script type="text/javascript">
function SetTimeStamp()
{
 	'<%Session("TimeStamp") = time%>';
}
</script>

<body>
<center><b>Testar Boto Back</b></center>

<%
Sub PedeReg
	%>
	<form action="Back-Button.asp?faz=aaa" method="post">
		Pede Registo <br>
		<input type="submit" value="Ok">
	</form>
	<%
	set session("TimeStamp") = nothing
end sub

Sub Formulario
	%>
	<form action="Back-Button.asp?faz=bbb" method="post">
		Formulrio <br>
		<%response.write("<br>Pede Registo: "&time&"<br>")%>
		<input type="submit" onClick="SetTimeStamp()" value="Ok">
	</form>
	<%
end sub


Sub GuardaDados
	response.write("Dados Guardados<br>")
	response.write("session('TimeStamp'): " & session("TimeStamp") & "<br>")
	response.write("Time: " & Time & "<br><hr>")
	set session("TimeStamp") = nothing
end sub


'------- Corpo principal ---------
Select case request.querystring("faz")
	Case "aaa"
		formulario
	Case "bbb"
		if session("TimeStamp")=time then
			GuardaDados
		else
			response.write("Sesso expirada ou boto foi usado boto para retroceder")
		end if
		PedeReg
	Case else
		PedeReg
end select
%>

</body>

 

Link to comment
Share on other sites

"Classic ASP"... cheguei a trabalhar nisto há muito, muito, muito, muito, muito, ... tempo atrás.... e não me lembro de propriamente ter tido um problema semelhante, mas também já passou tanto tempo que já nem tenho as "sources" para ir espreitar como fazia.

Sei que havia uma situação em que precisaria invalidar as "caches" e forçar o reload/refresh e agora numa pesquisa Google, lembro-me que seria algo assim:

https://stackoverflow.com/questions/15377975/reloading-page-when-the-user-clicks-on-the-back-button-in-browser

Dado o seu problema, penso que faz submission (self), não seria esta a solução (pesquisa Google):

https://stackoverflow.com/questions/10674933/how-to-check-form-submission-asp-classic

No meu caso (antigo)... já não tenho a certeza... mas penso que faria submission (outro url) !? mesmo que regressassem (back) o "invalidate cache"  mostraria a informação +actual ou seja ficava a consultar a nova informação e pronta para ser (novamente) alterada.

.. por curiosidade, porque "Classic ASP"? é algum curso/formação? 

cps,

Link to comment
Share on other sites

1 hora atrás, antseq disse:

.. por curiosidade, porque "Classic ASP"? é algum curso/formação? 

cps,

Off Topic

Looooong story!

Comecei no Pascal, evolui para o Delphi e depois para partilhar informação entre máquinas Windows e UNIX "descobri" que as páginas dinâmicas. Problemas? Necessitava de uma linguagem que não tivesse de aprender toda a programação de raiz; Servidor interno livre (não pago); acesso a bases de dados que se pudessem construir com um front end simples e pudesse colocar as BD onde queria e não num repositório pré-definido.

Depois de alguns testes com servidores, descobri o IIS que estava a dar os primeiros passos que utilizava o VBScript (linguagem muito parecida com Pascal / Delphi) e que dava para integrar bases de dados MS-Access em DSN-Less, isto é pode estar na pasta que eu quizer.

Depois foi só programar e programar o portal interno da empresa e agora para se alterar tem de se reprogramar todos os sites e sub-sites internos, módulos e mais módulos. Aliás tenho algumas funcionalidades que eram gratuitas e agora para os servidores novos são pagas. leitores e criadores de códigos QR, criadores de PDF's, etc.

Sei que é tudo antigo, mas tudo funciona bem e rápido... até que alguém resolveu fazer "back" várias vezes 😞

 

Link to comment
Share on other sites

@passaritocomo expliquei anteriormente, a opção de client-side não é opção. Na verdade o back é detetado precisamente pela discrepância entre timestamps.
Creio que há ai alguma confusão / falhas de conhecimento.
Há uma parte da tua aplicação que corre no servidor e uma parte que corre no browser. Toda a solução que te indiquei corre exclusivamente no servidor, não vais conseguir detetar isso apenas no browser (na verdade o browser não faz sequer parte da solução).

Creio que devias aprender primeiro algumas noções básicas de desenvolvimento web antes de tentares fazer o que quer que seja.

10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Link to comment
Share on other sites

@M6 não te julgava tão agressivo, tem calma, nem todos podemos ser "experts". Aproveito para pedir desculpa se disse alguma coisa menos agradável. Podemos continuar sem bate-boca?

 

Encontrei uma pseudo-solução, criei um ficheiro com o nome "Aviod-BB.ASP" apenas com uma linha:

response.Redirect(request.querystring("ficheiro"))

No ficheiro principal de pois de gravar os dados chamo este ficheiro que depois volta a redirecionar para o principal:

response.redirect("Avoid-BB.ASP?ficheiro=Back-Button.asp&faz=---")

 

Além de funcionar, estou interessado na tua perspetiva @M6, será que isto é viável?

<script type="text/javascript">

Var TS="";
function SetTimeStamp()
{
	TS=Date.now() / 1000;
}

function CompareTimeStamp()
{
	if TS==Date.now() / 1000;
  	{ CompareTimeStamp=True  }  
  	else
  	{ CompareTimeStamp=False  }  
}
</script>

Chamando o SetTimeStamp no botão ok do formulário e o CompareTimeStamp quando vai guardar os dados. TS Seria uma variável global.

Ou isto está tudo errado?

Link to comment
Share on other sites

@passarito, quando se escreve e lê, a mensagem - tipicamente - não passa com expressão/entoação e por vezes pode ser mal compreendida.
Não há nada de agressivo nas minhas respostas, nem tens de pedir de desculpa pela ignorância, ninguém nasce ensinado, mas todos nascemos ignorantes.
O que disse anteriormente, continua a ser relevante: devias aprender primeiro algumas noções básicas de desenvolvimento web antes de tentares fazer o que quer que seja.
O que quero dizer com isto é que não se pode correr antes de aprender a andar, caso contrário vamos andar sempre aos tropeções.
 

Quanto à tua solução, continuas a querer validar no lado do cliente, em Javascript, mas quando trocas de página, perdes o contexto.
O facto da variável ser global (algo que deves evitar a todo o custo), o seu valor perde-se entre chamadas ao servidor porque a variável global não quer dizer que seja persistente.
Para teres um valor persistente usando exclusivamente o lado do cliente (leia-se no browser) tens de recorrer a um mecanismo de persistência, por exemplo, usando cookies.

Quanto aos redirects, honestamente, não compreendo a ideia. Se fizer back continuo a poder andar para trás no browser e no lado do servidor não vejo nada que detete que o pedido deve ser tido em conta ou descartado.

Edited by M6
10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Link to comment
Share on other sites

Boas,

Cá estou eu outra vez.

Não sei se estarei a fazer algum erro, ou se isto não funciona de todo.

Quando clico no "ok" do formulário o programa cria/atualiza o timestamp do cookie. Quando vai gravar compara o timestamp do cookie com a hora atual. Até aqui funciona.

Quando está a página posterior ao "Gravar dados" e se faz "Back" o browser carrega a página "Gravar dados" sem ir verificar o timestamp do cookie nem a hora atual, passando sempre por cima da comparação.

Inclusivamente, forcei uma diferença entre o timestamp do cookie e a hora do sistema para verificar a comparação e ele, como esperado retorna o erro, portanto o "if" com a comparação está a funcionar bem.

Há aqui alguma coisa que me está a escapar?

Link to comment
Share on other sites

Quando entras numa páginas deves ter no cookie o timestamp da última operação e se tiveres no url um timestamp, também consegues fazer isso.

Talvez haja uma forma mais simples de compreender/implementar usando um contador.

  1. Quando chegas ao teu site podes inicias um contador a zero que vais guardar numa cookie e vais passar no url entre todas as páginas.
  2. Quando avanças para a página seguinte adicionas 1 ao contador, guardas esse valor na cookie e passas o mesmo no URL da página. Ou seja, quando entras na página onde tens "Gravar Dados" adicionas 1 ao contador que tens na cookie; quando carregas no botão "Gravar Dados" avanças para a página seguinte levando no URL o valor do contador que tens na cookie.
  3. Quando entras numa página, verficas se o contador que tens na cookie é igual ao que tens no URL, se não for, então aconteceu um back.


Exemplo:

Entras no teu site, por exemplo http://localhost verificas se existe um cookie de contador, se existir colocas a 0 se não existir crias com o valor 0.

Quando clicas num link (antes de saires da página onde estás), vais ler o cookie do contador, adicionas 1, gravas o cookie com o novo valor e passas no URL o novo valor do cookie.
Estando o contador a 0, ao clicares para ires para a página "batatas", o cookie do contador passaria a 1 e colocarias também 1 no url, por exemplo http://localhost/batatas?contador=1

Quando entras na página "batatas", confirmas que valor do contador do cookie bate certo com o valor do contador que passaste no URL, ambos têm o valor 1, pelo que está tudo coerente.

Agora clicas num novo link (antes de saires da página onde estás), vais ler o cookie do contador, adicionas 1, gravas o cookie com o novo valor e passas no URL o novo valor do cookie.
Estando o contador a 1, ao clicares para ires para a página "fritas", o cookie do contador passaria a 2 e colocarias também 2 no url, por exemplo http://localhost/fritas?contador=2

Quando entras na página "fritas" confirmas que valor do contador do cookie bate certo com o valor do contador que passaste no URL, ambos têm o valor 2, pelo que está tudo coerente.

Agora fazes back.

Vais entras na página "batatas" (que está no teu histórico como http://localhost/batatas?contador=1), vais ver que o valor do contador do cookie não bate certo com o valor do contador que passaste no URL.
O valor do contador que está no cookie tem o valor 2.
O valor que tens no contador do URL tem o valor 1 (http://localhost/batatas?contador=1)
Isto não bate certo, está desincronizado. Percebes que o contador do URL é diferente (neste caso mais antigo) do que o contador do cookie.

 

Honestamente isto é significativamente mais complexo do que implementar um mecanismo destes usando a sessão no servidor.
Estás a meter cookies e vais ter de lidar com a gestão do seu tempo de vida etc. o que só vai criar uma enorme carga de complexidade e de trabalho perfeitamente desnecessária.

10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.