Repository: AlistGo/alist (language: go)

Issue:
飞机盘 获取不到下载地址了，能进入列表页面
### Please make sure of the following things

- [X] I have read the [documentation](https://alist.nn.ci).
我已经阅读了[文档](https://alist.nn.ci)。

- [X] I'm sure there are no duplicate issues or discussions.
我确定没有重复的issue或讨论。

- [X] I'm sure it's due to `AList` and not something else(such as [Network](https://alist.nn.ci/faq/howto.html#tls-handshake-timeout-read-connection-reset-by-peer-dns-lookup-failed-connect-connection-refused-client-timeout-exceeded-while-awaiting-headers-no-such-host) ,`Dependencies` or `Operational`).
我确定是`AList`的问题，而不是其他原因（例如[网络](https://alist.nn.ci/zh/faq/howto.html#tls-handshake-timeout-read-connection-reset-by-peer-dns-lookup-failed-connect-connection-refused-client-timeout-exceeded-while-awaiting-headers-no-such-host)，`依赖`或`操作`）。

- [X] I'm sure this issue is not fixed in the latest version.
我确定这个问题在最新版本中没有被修复。


### AList Version / AList 版本

3.33.0

### Driver used / 使用的存储驱动

FEIJIPAN

### Describe the bug / 问题描述

进入点击文件下载提示
failed link: failed get link: redirect failed, status: 200

### Reproduction / 复现链接

哪位大佬修复一下

### Config / 配置

哪位大佬修复一下

### Logs / 日志

_No response_


Discussion / hints:
一样    能获取列表  但是打开文件提示 failed link: failed get link: redirect failed, status: 200
一样
同
同问

failed link: failed get link: redirect failed, status: 200
同问
求更
你们开会员没
> 你们开会员没

我开了
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

1

Fix patch:
diff --git a/drivers/ilanzou/driver.go b/drivers/ilanzou/driver.go
index 63d86363962..ab5ebe7ee5d 100644
--- a/drivers/ilanzou/driver.go
+++ b/drivers/ilanzou/driver.go
@@ -66,18 +66,18 @@ func (d *ILanZou) Drop(ctx context.Context) error {
 }
 
 func (d *ILanZou) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
-	offset := 1
-	limit := 60
 	var res []ListItem
 	for {
 		var resp ListResp
 		_, err := d.proved("/record/file/list", http.MethodGet, func(req *resty.Request) {
-			req.SetQueryParams(map[string]string{
-				"type":     "0",
-				"folderId": dir.GetID(),
-				"offset":   strconv.Itoa(offset),
-				"limit":    strconv.Itoa(limit),
-			}).SetResult(&resp)
+			params := []string{
+				"offset=1",
+				"limit=60",
+				"folderId=" + dir.GetID(),
+				"type=0",
+			}
+			queryString := strings.Join(params, "&")
+			req.SetQueryString(queryString).SetResult(&resp)
 		})
 		if err != nil {
 			return nil, err
@@ -86,7 +86,6 @@ func (d *ILanZou) List(ctx context.Context, dir model.Obj, args model.ListArgs)
 		if resp.TotalPage <= resp.Offset {
 			break
 		}
-		offset++
 	}
 	return utils.SliceConvert(res, func(f ListItem) (model.Obj, error) {
 		updTime, err := time.ParseInLocation("2006-01-02 15:04:05", f.UpdTime, time.Local)
@@ -118,31 +117,33 @@ func (d *ILanZou) Link(ctx context.Context, file model.Obj, args model.LinkArgs)
 	if err != nil {
 		return nil, err
 	}
-	query := u.Query()
-	query.Set("uuid", d.UUID)
-	query.Set("devType", "6")
-	query.Set("devCode", d.UUID)
-	query.Set("devModel", "chrome")
-	query.Set("devVersion", d.conf.devVersion)
-	query.Set("appVersion", "")
-	ts, err := getTimestamp(d.conf.secret)
-	if err != nil {
-		return nil, err
+	ts, ts_str, err := getTimestamp(d.conf.secret)
+
+	params := []string{
+		"uuid=" + url.QueryEscape(d.UUID),
+		"devType=6",
+		"devCode=" + url.QueryEscape(d.UUID),
+		"devModel=chrome",
+		"devVersion=" + url.QueryEscape(d.conf.devVersion),
+		"appVersion=",
+		"timestamp=" + ts_str,
+		"appToken=" + url.QueryEscape(d.Token),
+		"enable=0",
 	}
-	query.Set("timestamp", ts)
-	query.Set("appToken", d.Token)
-	query.Set("enable", "1")
+
 	downloadId, err := mopan.AesEncrypt([]byte(fmt.Sprintf("%s|%s", file.GetID(), d.userID)), d.conf.secret)
 	if err != nil {
 		return nil, err
 	}
-	query.Set("downloadId", hex.EncodeToString(downloadId))
-	auth, err := mopan.AesEncrypt([]byte(fmt.Sprintf("%s|%d", file.GetID(), time.Now().UnixMilli())), d.conf.secret)
+	params = append(params, "downloadId="+url.QueryEscape(hex.EncodeToString(downloadId)))
+
+	auth, err := mopan.AesEncrypt([]byte(fmt.Sprintf("%s|%d", file.GetID(), ts)), d.conf.secret)
 	if err != nil {
 		return nil, err
 	}
-	query.Set("auth", hex.EncodeToString(auth))
-	u.RawQuery = query.Encode()
+	params = append(params, "auth="+url.QueryEscape(hex.EncodeToString(auth)))
+
+	u.RawQuery = strings.Join(params, "&")
 	realURL := u.String()
 	// get the url after redirect
 	res, err := base.NoRedirectClient.R().SetHeaders(map[string]string{
@@ -156,12 +157,7 @@ func (d *ILanZou) Link(ctx context.Context, file model.Obj, args model.LinkArgs)
 	if res.StatusCode() == 302 {
 		realURL = res.Header().Get("location")
 	} else {
-		contentLengthStr := res.Header().Get("Content-Length")
-		contentLength, err := strconv.Atoi(contentLengthStr)
-		if err != nil || contentLength == 0 || contentLength > 1024*10 {
-			return nil, fmt.Errorf("redirect failed, status: %d", res.StatusCode())
-		}
-		return nil, fmt.Errorf("redirect failed, content: %s", res.String())
+		return nil, fmt.Errorf("redirect failed, status: %d, msg: %s", res.StatusCode(), utils.Json.Get(res.Body(), "msg").ToString())
 	}
 	link := model.Link{URL: realURL}
 	return &link, nil
@@ -179,7 +175,7 @@ func (d *ILanZou) MakeDir(ctx context.Context, parentDir model.Obj, dirName stri
 		return nil, err
 	}
 	return &model.Object{
-		ID: utils.Json.Get(res, "list", "0", "id").ToString(),
+		ID: utils.Json.Get(res, "list", 0, "id").ToString(),
 		//Path:     "",
 		Name:     dirName,
 		Size:     0,
@@ -348,10 +344,12 @@ func (d *ILanZou) Put(ctx context.Context, dstDir model.Obj, stream model.FileSt
 	var resp UploadResultResp
 	for i := 0; i < 10; i++ {
 		_, err = d.unproved("/7n/results", http.MethodPost, func(req *resty.Request) {
-			req.SetQueryParams(map[string]string{
-				"tokenList": token,
-				"tokenTime": time.Now().Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)"),
-			}).SetResult(&resp)
+			params := []string{
+				"tokenList=" + token,
+				"tokenTime=" + time.Now().Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)"),
+			}
+			queryString := strings.Join(params, "&")
+			req.SetQueryString(queryString).SetResult(&resp)
 		})
 		if err != nil {
 			return nil, err
diff --git a/drivers/ilanzou/util.go b/drivers/ilanzou/util.go
index c9a30765b7f..a57e2a4a6be 100644
--- a/drivers/ilanzou/util.go
+++ b/drivers/ilanzou/util.go
@@ -4,7 +4,9 @@ import (
 	"encoding/hex"
 	"fmt"
 	"net/http"
+	"net/url"
 	"strconv"
+	"strings"
 	"time"
 
 	"github.com/alist-org/alist/v3/drivers/base"
@@ -31,45 +33,52 @@ func (d *ILanZou) login() error {
 	return nil
 }
 
-func getTimestamp(secret []byte) (string, error) {
+func getTimestamp(secret []byte) (int64, string, error) {
 	ts := time.Now().UnixMilli()
 	tsStr := strconv.FormatInt(ts, 10)
 	res, err := mopan.AesEncrypt([]byte(tsStr), secret)
 	if err != nil {
-		return "", err
+		return 0, "", err
 	}
-	return hex.EncodeToString(res), nil
+	return ts, hex.EncodeToString(res), nil
 }
 
 func (d *ILanZou) request(pathname, method string, callback base.ReqCallback, proved bool, retry ...bool) ([]byte, error) {
-	req := base.RestyClient.R()
-	ts, err := getTimestamp(d.conf.secret)
+	_, ts_str, err := getTimestamp(d.conf.secret)
 	if err != nil {
 		return nil, err
 	}
-	req.SetQueryParams(map[string]string{
-		"uuid":       d.UUID,
-		"devType":    "6",
-		"devCode":    d.UUID,
-		"devModel":   "chrome",
-		"devVersion": d.conf.devVersion,
-		"appVersion": "",
-		"timestamp":  ts,
-		//"appToken":   d.Token,
-		"extra": "2",
-	})
+
+	params := []string{
+		"uuid=" + url.QueryEscape(d.UUID),
+		"devType=6",
+		"devCode=" + url.QueryEscape(d.UUID),
+		"devModel=chrome",
+		"devVersion=" + url.QueryEscape(d.conf.devVersion),
+		"appVersion=",
+		"timestamp=" + ts_str,
+	}
+
+	if proved {
+		params = append(params, "appToken="+url.QueryEscape(d.Token))
+	}
+
+	params = append(params, "extra=2")
+
+	queryString := strings.Join(params, "&")
+
+	req := base.RestyClient.R()
 	req.SetHeaders(map[string]string{
 		"Origin":     d.conf.site,
 		"Referer":    d.conf.site + "/",
 		"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0",
 	})
-	if proved {
-		req.SetQueryParam("appToken", d.Token)
-	}
+
 	if callback != nil {
 		callback(req)
 	}
-	res, err := req.Execute(method, d.conf.base+pathname)
+
+	res, err := req.Execute(method, d.conf.base+pathname+"?"+queryString)
 	if err != nil {
 		if res != nil {
 			log.Errorf("[iLanZou] request error: %s", res.String())


Test patch: