Um valor ou o endereço inteiro
Os dois modos diferem em cinco caracteres: &, =, ?, / e #.
Um valor escapa todos eles. Use para o que vai dentro de um parâmetro: um termo de busca, um destino de redirecionamento. Coloque uma URL sem escape depois de ?next= e o & que ela carrega será lido como o começo de um novo parâmetro, cortando o seu valor.
Endereço inteiro deixa os caracteres estruturais em paz. Serve quando você já tem uma URL que funciona e só quer limpar espaços e caracteres não ASCII. Passando o endereço completo por este modo, as barras de https:// sobrevivem e o link continua funcionando.
Uma regra resolve: montando parte de um endereço, use um valor; já tendo o endereço, use endereço inteiro.
Espaços: + ou %20
Você vai ver os dois, mas eles pertencem a lugares diferentes. %20 é a forma padrão e vale em qualquer ponto de uma URL. + vem da codificação antiga de formulários HTML e só conta como espaço dentro de uma query string.
Um + no caminho é um sinal de mais literal. Decodifique um nome de arquivo com as regras de formulário e você o renomeia sem perceber. Esta ferramenta segue o padrão e gera %20.
Valores codificados duas vezes
Se a decodificação deixa %2520 ou %253A, o valor foi codificado duas vezes: na segunda passada o próprio % virou %25.
Costuma acontecer quando o código codifica um valor que já vinha codificado. Decodificar mais uma vez devolve o texto, mas o conserto de verdade é decidir onde a codificação acontece: uma única vez, no ponto em que o valor entra na URL, e texto puro no resto do caminho.
Caracteres que ficam como estão
A-Z, a-z, 0-9 e -, ., _, ~ formam o conjunto não reservado: a especificação os marca como seguros e eles passam intactos. Vê-los sem mudança não é defeito.
Caracteres não ASCII se expandem: uma vogal acentuada ocupa dois bytes UTF-8, um caractere chinês três e um emoji quatro, e cada byte vira um par %XX. É por isso que um endereço codificado fica de repente tão comprido.