Files
2026-05-12 07:58:30 +00:00

81 lines
2.0 KiB
Go

package main
import (
"errors"
"net/http"
"strings"
"github.com/duke-git/lancet/v2/validator"
"github.com/gin-gonic/gin"
"resty.dev/v3"
)
// newServer 创建并配置 HTTP 服务。
func newServer(db *DB, client *resty.Client) *gin.Engine {
gin.SetMode(gin.ReleaseMode)
server := gin.Default()
server.Use(corsMiddleware())
registerRoutes(server, db, client)
return server
}
// corsMiddleware 允许浏览器跨域访问接口。
func corsMiddleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", "*")
ctx.Header("Access-Control-Allow-Methods", "GET, OPTIONS")
ctx.Header("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization")
if ctx.Request.Method == http.MethodOptions {
ctx.AbortWithStatus(http.StatusNoContent)
return
}
ctx.Next()
}
}
// registerRoutes 注册当前服务公开的 HTTP 路由。
func registerRoutes(server *gin.Engine, db *DB, client *resty.Client) {
server.GET("/", handleArticleRequest(db, client))
}
// handleArticleRequest 处理文章查询请求:校验参数,读取缓存或抓取源站。
func handleArticleRequest(db *DB, client *resty.Client) gin.HandlerFunc {
return func(ctx *gin.Context) {
articleID := strings.TrimSpace(ctx.Query("article_id"))
if articleID == "" {
ctx.JSON(http.StatusNotFound, response{Ok: false})
return
}
if !validator.IsNumberStr(articleID) {
ctx.JSON(http.StatusBadRequest, response{
Ok: false,
Error: "article_id 应为数字",
})
return
}
html, err := getArticleHTML(db, client, articleID)
if err != nil {
ctx.JSON(articleErrorStatusCode(err), createErr(err))
return
}
ctx.JSON(http.StatusOK, response{
Ok: true,
Html: html,
})
}
}
// articleErrorStatusCode 将文章抓取错误映射为合适的 HTTP 状态码。
func articleErrorStatusCode(err error) int {
if errors.Is(err, errArticleContentNotFound) || errors.Is(err, errArticleContentParseFailed) {
return http.StatusNotFound
}
return http.StatusInternalServerError
}