You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

143 lines
3.7 KiB

package store
import (
"fmt"
"io"
"net/http"
"regexp"
"strings"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
)
type PageState struct {
URL string `json:"url"`
History []string
Index int
}
var pageState = &PageState{}
func browserNavigate(url string) {
// 启动浏览器
launch := launcher.New().Headless(false) // 设置为 false 可以看到浏览器界面
browser := rod.New().ControlURL(launch.MustLaunch()).MustConnect()
//defer browser.MustClose()
// 打开一个页面
// page := browser.MustPage(url)
// page.MustWaitLoad()
browser.MustPage(url)
}
func fetchPageContent(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
html := string(body)
// 插入 <base> 标签
baseTag := fmt.Sprintf("<base href=\"%s\" />", url)
html = strings.Replace(html, "<head>", fmt.Sprintf("<head>%s", baseTag), 1)
// 过滤掉可能引起弹窗的脚本
re := regexp.MustCompile(`(window\.open)\(.*?\);`)
html = re.ReplaceAllString(html, "")
// 移除或修改 a 标签的 target="_blank" 属性
reA := regexp.MustCompile(`(<a[^>]*?)\s*target\s*=\s*"?_blank"?`)
html = reA.ReplaceAllString(html, "$1")
// 移除 X-Frame-Options 和 Content-Security-Policy 头
resp.Header.Del("X-Frame-Options")
resp.Header.Del("Content-Security-Policy")
html += `<script>
window.onload = function() {
window.parent.postMessage(window.location.href, '*');
};
</script>`
return html, nil
}
func HandleNavigate(w http.ResponseWriter, r *http.Request) {
url := r.URL.Query().Get("url")
if url == "" {
http.Error(w, "URL parameter is required", http.StatusBadRequest)
return
}
browserNavigate(url)
// html, err := fetchPageContent(url)
// if err != nil {
// http.Error(w, err.Error(), http.StatusInternalServerError)
// return
// }
// pageState.History = append(pageState.History, url)
// pageState.Index = len(pageState.History) - 1
// pageState.URL = url
// w.Header().Set("Content-Type", "text/html; charset=utf-8")
// fmt.Fprint(w, html)
}
func HandleBack(w http.ResponseWriter, r *http.Request) {
if pageState.Index > 0 {
pageState.Index--
url := pageState.History[pageState.Index]
html, err := fetchPageContent(url)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
pageState.URL = url
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprint(w, html)
} else {
http.Error(w, "No more history to go back", http.StatusForbidden)
}
}
func HandleForward(w http.ResponseWriter, r *http.Request) {
if pageState.Index < len(pageState.History)-1 {
pageState.Index++
url := pageState.History[pageState.Index]
html, err := fetchPageContent(url)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
pageState.URL = url
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprint(w, html)
} else {
http.Error(w, "No more history to go forward", http.StatusForbidden)
}
}
func HandleRefresh(w http.ResponseWriter, r *http.Request) {
if pageState.URL != "" {
html, err := fetchPageContent(pageState.URL)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprint(w, html)
} else {
http.Error(w, "No current URL to refresh", http.StatusForbidden)
}
}
// func main() {
// http.HandleFunc("/navigate", HandleNavigate)
// http.HandleFunc("/back", HandleBack)
// http.HandleFunc("/forward", HandleForward)
// http.HandleFunc("/refresh", HandleRefresh)
//
// http.ListenAndServe(":8080", nil)
// }