Quiero crear un servicio de acortador de URL donde pueda escribir una URL larga en un campo de entrada y el servicio acorta la URL a " http://www.example.org/abcdef
".
En lugar de " abcdef
" puede haber cualquier otra cadena que contenga seis caracteres a-z, A-Z and 0-9
. Eso hace que 56 ~ 57 mil millones de cadenas posibles.
Mi acercamiento:
Tengo una tabla de base de datos con tres columnas:
- id, entero, incremento automático
- long, string, la URL larga que ingresó el usuario
- short, string, la URL acortada (o solo los seis caracteres)
Luego insertaría la URL larga en la tabla. Luego seleccionaría el valor de incremento automático para " id
" y crearía un hash de él. Este hash se debe insertar como " short
". Pero, ¿qué tipo de hash debo construir? Algoritmos hash como MD5 crean cadenas demasiado largas. No uso estos algoritmos, creo. Un algoritmo de construcción propia también funcionará.
Mi idea:
Para " http://www.google.de/
" obtengo la identificación de incremento automático 239472
. Luego hago los siguientes pasos:
short = '';
if divisible by 2, add "a"+the result to short
if divisible by 3, add "b"+the result to short
... until I have divisors for a-z and A-Z.
Eso podría repetirse hasta que el número ya no sea divisible. ¿Crees que este es un buen enfoque? Tienes una mejor idea?
Debido al continuo interés en este tema, he publicado una solución eficiente para GitHub , con implementaciones para JavaScript , PHP , Python y Java . Agregue sus soluciones si lo desea :)
encode()
ydecode()
funciones. Los pasos son, por lo tanto: (1) Guardar URL en la base de datos (2) Obtener una ID de fila única para esa URL de la base de datos (3) Convertir la ID entera en una cadena corta conencode()
, por ejemplo,273984
af5a4
(4) Usar la cadena corta (por ejemplof4a4
) en su URL compartibles (5) Al recibir una solicitud de una cadena corta (p20a8
. ej. ), decodifique la cadena a una ID entera condecode()
(6) Buscar URL en la base de datos para la ID dada. Para la conversión, use: github.com/delight-im/ShortURLRespuestas:
Continuaría con tu enfoque de "convertir número a cadena". Sin embargo, se dará cuenta de que su algoritmo propuesto falla si su ID es primo y mayor que 52 .
Antecedentes teóricos
Necesita una función biyectiva f . Esto es necesario para que pueda encontrar una función inversa g ('abc') = 123 para su función f (123) = 'abc' . Esto significa:
Cómo convertir la ID a una URL acortada
[a-zA-Z0-9]
. Contiene 62 letras .Tome una clave numérica única y autogenerada (el autoincrementado
id
de una tabla MySQL, por ejemplo).Para este ejemplo, usaré 125 10 (125 con una base de 10).
Ahora tienes que convertir 125 10 a X 62 (base 62).
125 10 = 2 × 62 1 + 1 × 62 0 =
[2,1]
Esto requiere el uso de división entera y módulo. Un ejemplo de pseudocódigo:
Ahora asigna los índices 2 y 1 a tu alfabeto. Así es como podría verse su mapeo (con una matriz, por ejemplo):
Con 2 → c y 1 → b, recibirá cb 62 como la URL acortada.
Cómo resolver una URL acortada a la ID inicial
Lo contrario es aún más fácil. Simplemente haces una búsqueda inversa en tu alfabeto.
e9a 62 se resolverá como "4ª, 61ª y 0ª letra del alfabeto".
e9a 62 =
[4,61,0]
= 4 × 62 2 + 61 × 62 1 + 0 × 62 0 = 19158 10Ahora encuentre su registro de base de datos
WHERE id = 19158
y realice la redirección.Implementaciones de ejemplo (proporcionadas por comentaristas)
fuente
3792586=='F_ck'
con u en lugar de _). Excluiría algunos caracteres como u / U para minimizar esto.¿Por qué querrías usar un hash?
Simplemente puede usar una traducción simple de su valor de incremento automático a un valor alfanumérico. Puede hacerlo fácilmente utilizando alguna conversión base. Digamos que el espacio de caracteres (AZ, az, 0-9, etc.) tiene 40 caracteres, convierta la identificación a un número base 40 y use los caracteres como dígitos.
fuente
fuente
No es una respuesta a su pregunta, pero no usaría URL acortadas que distingan entre mayúsculas y minúsculas. Son difíciles de recordar, generalmente ilegibles (muchas fuentes representan 1 y 1, 0 y O y otros caracteres muy similares a los que son casi imposibles de diferenciar) y francamente propensos a errores. Intente usar minúsculas o mayúsculas solamente.
Además, intente tener un formato donde mezcle los números y caracteres en una forma predefinida. Hay estudios que muestran que las personas tienden a recordar un formulario mejor que otros (piense en los números de teléfono, donde los números se agrupan en un formulario específico). Pruebe algo como num-char-char-num-char-char. Sé que esto reducirá las combinaciones, especialmente si no tiene mayúsculas y minúsculas, pero sería más útil y, por lo tanto, útil.
fuente
Mi enfoque: tomar la identificación de la base de datos, luego codificarla en Base36 . NO usaría letras mayúsculas y minúsculas, porque eso hace que transmitir esas URL por teléfono sea una pesadilla, pero por supuesto, podría extender fácilmente la función para que sea un decodificador / base 62.
fuente
Aquí está mi clase PHP 5.
fuente
Una solución Node.js y MongoDB
Dado que conocemos el formato que utiliza MongoDB para crear un nuevo ObjectId con 12 bytes.
Ejemplo (elijo una secuencia aleatoria) a1b2c3d4e5f6g7h8i9j1k2l3
Dado que el contador será único si almacenamos los datos en la misma máquina, podemos obtenerlo sin dudas de que se duplicará.
Entonces, la URL corta será el contador y aquí hay un fragmento de código que supone que su servidor se está ejecutando correctamente.
fuente
Versión C #:
fuente
Puede hacer un hash de la URL completa, pero si solo quiere acortar la identificación, haga lo que sugirió Marcel. Escribí esta implementación de Python:
https://gist.github.com/778542
fuente
Sigo incrementando una secuencia de enteros por dominio en la base de datos y uso Hashids para codificar el entero en una ruta URL.
Ejecuté un script para ver cuánto tiempo lleva hasta que agota la longitud del personaje. Para seis caracteres puede hacer
164,916,224
enlaces y luego sube a siete caracteres. Bitly usa siete caracteres. Menos de cinco personajes me parecen extraños.Los hashids pueden decodificar la ruta de la URL de regreso a un entero, pero una solución más simple es usar el enlace corto completo
sho.rt/ka8ds3
como clave principal.Aquí está el concepto completo:
fuente
Si no quieres reinventar la rueda ... http://lilurl.sourceforge.net/
fuente
fuente
Aquí está mi versión para quien la necesite.
fuente
Eche un vistazo a https://hashids.org/ es de código abierto y en muchos idiomas.
Su página describe algunas de las trampas de otros enfoques.
fuente
¿Por qué no solo traducir su identificación a una cadena? Solo necesita una función que asigne un dígito entre, digamos, 0 y 61 a una sola letra (mayúscula / minúscula) o dígito. Luego aplique esto para crear, digamos, códigos de 4 letras, y tendrá 14.7 millones de URL cubiertas.
fuente
Aquí hay una función de codificación de URL decente para PHP ...
fuente
No sé si alguien encontrará esto útil: es más un método de 'hack n slash', pero es simple y funciona bien si solo desea caracteres específicos.
fuente
¿Omitiste O, 0 e i a propósito?
Acabo de crear una clase PHP basada en la solución de Ryan.
fuente
Esto es lo que uso:
Es muy rápido y puede tomar enteros largos.
fuente
Para un proyecto similar, para obtener una nueva clave, hago una función de envoltura alrededor de un generador de cadenas al azar que llama al generador hasta que obtengo una cadena que aún no se ha utilizado en mi tabla hash. Este método se ralentizará una vez que su espacio de nombres comience a llenarse, pero como ha dicho, incluso con solo 6 caracteres, tiene mucho espacio de nombres para trabajar.
fuente
Tengo una variante del problema, ya que almaceno páginas web de muchos autores diferentes y necesito evitar el descubrimiento de páginas por conjeturas. Entonces, mis URL cortas agregan un par de dígitos adicionales a la cadena Base-62 para el número de página. Estos dígitos adicionales se generan a partir de la información en el registro de la página y aseguran que solo 1 de cada 3844 URL sean válidos (suponiendo Base-62 de 2 dígitos). Puede ver una descripción general en http://mgscan.com/MBWL .
fuente
Muy buena respuesta, he creado una implementación de Golang de bjf:
Alojado en github: https://github.com/xor-gate/go-bjf
fuente
fuente
Implementación en Scala:
Ejemplo de prueba con la prueba Scala:
fuente
Función basada en la clase Xeoncross
fuente
Aquí hay una implementación de Node.js que probablemente bit.ly. generar una cadena de siete caracteres altamente aleatoria.
Utiliza el cripto Node.js para generar un conjunto de 25 caracteres altamente aleatorio en lugar de seleccionar aleatoriamente siete caracteres.
fuente
Mi versión de Python 3
fuente
Para obtener una solución Node.js / JavaScript de calidad, consulte el abreviador de id módulo , que se probó exhaustivamente y se ha utilizado en producción durante meses.
Proporciona un acortador eficiente de ID / URL respaldado por el almacenamiento enchufable predeterminado en Redis , e incluso puede personalizar su conjunto de caracteres de ID corto y si el acortamiento es idempotente . Esta es una distinción importante que no todos los acortadores de URL tienen en cuenta.
En relación con otras respuestas aquí, este módulo implementa la excelente respuesta aceptada de Marcel Jackwerth anterior.
El núcleo de la solución lo proporciona el siguiente fragmento de Redis Lua :
fuente
¿Por qué no solo generar una cadena aleatoria y agregarla a la URL base? Esta es una versión muy simplificada de hacer esto en C # .
Luego solo agregue el agregar la cadena aleatoria a la baseURL:
Recuerde que esta es una versión muy simplificada de hacer esto y es posible que el método RandomString pueda crear cadenas duplicadas. En producción, debe tener en cuenta las cadenas duplicadas para asegurarse de que siempre tendrá una URL única. Tengo un código que tiene en cuenta las cadenas duplicadas al consultar una tabla de base de datos que podría compartir si alguien está interesado.
fuente
Este es mi pensamiento inicial, y se puede hacer más pensamiento, o se puede hacer una simulación para ver si funciona bien o si se necesita alguna mejora:
Mi respuesta es recordar la URL larga en la base de datos y usar la ID
0
para9999999999999999
(o por grande que sea el número necesario).Pero el ID 0
9999999999999999
puede ser un problema, porqueA
-Z
a
-z
0
-9
_
y-
)0
a9999999999999999
uniforme, los piratas informáticos pueden visitarlos en ese orden y saber qué URL se envían entre sí, por lo que puede ser un problema de privacidadPodemos hacer esto:
0
a999
un servidor, el Servidor A, por lo que ahora el Servidor A tiene 1000 de tales ID. Entonces, si hay 20 o 200 servidores que desean constantemente nuevas ID, no tiene que seguir pidiendo cada nueva ID, sino más bien pedir una sola vez por 1000 ID000...00000001
convierte10000...000
, de modo que cuando se convierte a base64, aumentará de manera no uniforme las ID cada vez.0xD5AA96...2373
(como una clave secreta), y algunos bits se voltearán. (siempre que la clave secreta tenga el bit 1 activado, cambiará el bit de la ID). Esto hará que las identificaciones sean aún más difíciles de adivinar y parezcan más aleatoriasSiguiendo este esquema, el único servidor que asigna las ID puede formar las ID, y también los 20 o 200 servidores que solicitan la asignación de ID. El servidor de asignación tiene que usar un bloqueo / semáforo para evitar que dos servidores solicitantes obtengan el mismo lote (o si está aceptando una conexión a la vez, esto ya resuelve el problema). Por lo tanto, no queremos que la línea (cola) sea demasiado larga para esperar a obtener una asignación. Por eso, asignar 1000 o 10000 a la vez puede resolver el problema.
fuente