Создание собственного укорачивателя URL

Это своего рода полу-блог-полу-учебник о том, как создать свой URL-коротыш, используя Redis, go & GitHub copilot.

Введение

Я искал сервис для сокращения URL для своего домена, их много, например bit.ly, short.io, cutt.ly… но большинство из них платные или имеют много ограничений, например, количество URL.
Поэтому я решил создать свой собственный, для начала проекта мне нужно было знать

  1. Какой язык я буду использовать
  2. Как я буду хранить данныеДля первого варианта я решил использовать Go. Почему? Почему бы и нет? Это язык программирования, поэтому он подходит.Для второго проекта я решил использовать MongoDB, но это изменится в ближайшее время.Пока не зацикливайтесь на этом и начинайте кодить!

Настройка рабочего пространства

Вы можете скачать go cli здесь, но я более базирован, чем вы 😎 поэтому GitHub предоставил мне бета-версию Codespaces.
Если вы основаны, как я, перейдите в repo.new и создайте новое репо, не забудьте отметить это поле если вы хотите использовать Codespaces, после создания репо нажмите здесь, чтобы создать Codespace .

Для инициализации проекта выполните следующую команду go mod init shortener, это создаст go.mod. Что-то вроде package.json в node или Gemfile в rust.

Начните кодировать

Теперь начинайте кодировать!

Вставьте следующий код в файл main.go.

package main
import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/hello", hello)
    http.ListenAndServe(":8080", nil)
}

func hello(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello World!"))
}
Вход в полноэкранный режим Выйдите из полноэкранного режима

Это создаст http-сервер на порту 8080 и ответит на конечную точку /hello сообщением Hello World!.

Перенаправление

Что делает URL shortener? Перенаправляет пользователя на другой URL.

Для этого мы используем следующую строку кода

Реализация этого в нашем последнем коде выглядит следующим образом:

package main
import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/hello", HandleReq)
    http.ListenAndServe(":8080", nil)
}

func HandleReq(w http.ResponseWriter, r *http.Request) {
    http.Redirect(w, r, "https://www.google.com", http.StatusFound)
}
Вход в полноэкранный режим Выход из полноэкранного режима

Перенаправление url

Для чтения url мы используем следующую строку кода
r.URL.Path[len("/"):].
Внедрение этого кода в наш последний код выглядит следующим образом:

package main
import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/hello", HandleReq)
    http.ListenAndServe(":8080", nil)
}

func HandleReq(w http.ResponseWriter, r *http.Request) {
    key := r.URL.Path[len("/"):]

    http.Redirect(w, r, "https://www.google.com", http.StatusFound)
    fmt.Println(key)
}
Вход в полноэкранный режим Выход из полноэкранного режима

Реализация базы данных

Теперь, когда мы знаем, как читать url и перенаправлять, мы реализуем базу данных.

Для этого я подумал, что использование MongoDb — хорошая идея. Позвольте мне избавить вас от этих страданий, не используйте mongo.

Вместо него мы будем использовать Redis

Размещение базы данных

Знаете ли вы, как разместить базу данных Redis? Я не знаю.
Так что для этого я буду использовать Railway, он позволяет создать базу данных за несколько секунд, просто зайдите на https://railway.app/new & нажмите Provision redis, затем нажмите Redis -> Connect.
Появится URL вроде этого redis://default:password@host, сохраните эти данные.

ℹ В этом руководстве не рассматривается, как создавать URL программно **пока*, поэтому для создания URL перейдите в data и создайте ключи со значением URL, куда вы хотите перенаправить.*

Подключение к базе данных

Для этого мы будем использовать go-redis, для его установки запустите github.com/go-redis/redis/v8.

Для создания клиента мы будем использовать следующий код

redis.NewClient(&redis.Options{
        Addr:     server,
        Password: password,
        DB:       0,
    })
Вход в полноэкранный режим Выйти из полноэкранного режима

Для получения данных из базы данных мы будем использовать следующий код

value, err := db.Get(context.Background(), key).Result()
Войти в полноэкранный режим Выйти из полноэкранного режима

Реализация этого кода в нашем последнем коде выглядит следующим образом:

package main

import (
    "fmt"
    "net/http"
    "context"

    "github.com/go-redis/redis"
)
//This define db and context, why? In go if you want to make a global variable you need to define it outside the main function.
var db *redis.Client
var ctx = context.Background()

func main() {
    DataBase()
    http.HandleFunc("/", requestHandler)
    http.ListenAndServe(":"+port, nil)
    fmt.Println("Server started on port:", port)

}

func DataBase() {

    db = redis.NewClient(&redis.Options{
        Addr:     server,
        Password: password,
        DB:       0,
    })

    fmt.Println("Connected to Database")
}

func requestHandler(w http.ResponseWriter, r *http.Request) {
    //This get the key from the URL by wathing the url path and removing the `/`
    key := r.URL.Path[len("/"):]

    //this checks if the key is empty, if it's, return 404
    if r.URL.Path == "/" {
        http.Error(w, "Not Found", http.StatusNotFound)
        return
    }

    //this gets the value from the database
    value, err := db.Get(ctx, key).Result()

    //Go is kind of weir so if you want to know if there's a error you need to check if the value error value is not nil(null)
    if err != nil {
        panic(err)
    }
    //check if there is no URl for the key, if it's true, return 404
    if value == "" {
        http.Error(w, "Not Found", http.StatusNotFound)
        return
    }

    http.Redirect(w, r, value, http.StatusFound)
}
Вход в полноэкранный режим Выход из полноэкранного режима

Вот и все!
Теперь у нас есть полностью функциональный сократитель URL!

Надеюсь, вам понравился этот пост, если у вас есть вопросы или предложения не стесняйтесь Пожалуйста, комментируйте.

Оцените статью
Procodings.ru
Добавить комментарий