Cloudflare Worker添加Amazon推荐ID

根据你提供的”方案一”代码,它使用的是 Node.js 的 Express 框架 来构建的 Web 服务器。这是一个非常流行和灵活的 JavaScript 服务器框架。

🖥️ 核心组件与工作原理

方案一主要依赖以下核心库:

核心库 用途 版本建议
Express 作为Web应用框架,处理路由、中间件和HTTP请求/响应[citation:8] ^4.18.2
Axios 用于向亚马逊服务器发起HTTP请求,获取原始页面内容 ^1.6.0
Node.js 内置模块 (如 http, url) 提供基础的HTTP服务器和URL解析能力[citation:8] -

其工作原理如下图所示,可以看到一个请求是如何被处理的:

1
2
3
4
5
6
7
flowchart TD
A[用户访问你的服务器] --> B[Express 接收请求]
B --> C[Axios 向亚马逊请求原始页面]
C --> D{是否是HTML?}
D -- 是 --> E[正则匹配商品链接]
E --> F[添加联盟Tag后返回]
D -- 否 --> G[直接返回原始内容]

⚙️ 部署注意事项

要让这个服务器稳定运行,你需要:

  1. 安装依赖:在放代码的目录下运行 npm install express axios
  2. 启动服务:运行 node server.js。生产环境建议使用 PM2 等进程管理器来守护进程和实现零停机重启。
  3. 反向代理(可选但推荐):虽然你的代码本身是一个功能完整的Web服务器,但通常在生产环境中,强烈建议 在其前面搭配 Nginx[citation:5] 或 Caddy 这样的专业Web服务器作为反向代理。这样做能带来很多好处:
    • 提升性能:Nginx可以高效处理静态文件(如图片、CSS、JS)、SSL加密和解密,减轻Node.js进程的负担[citation:5]。
    • 增强安全性:隐藏后端Node.js服务器,提供额外的安全层。
    • 提高可靠性:可以做负载均衡,或者在你的Node.js应用意外崩溃时提供更优雅的错误处理。

一个简单的Nginx配置示例(/etc/nginx/sites-available/your-site)可能看起来像这样[citation:5]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
listen 80;
server_name your-domain.com; # 你的域名

location / {
proxy_pass http://localhost:3000; # 转发给本地运行的Node.js应用
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}

记得配置后通过 sudo nginx -t 测试配置,并用 sudo systemctl reload nginx 重载Nginx。

⚠️ 重要提醒

  • 正则表达式的局限性:代码中通过正则表达式匹配商品链接(匹配包含 /dp/ 后接10位字母数字的模式)并添加 &tag=audio-media-21。这种方式可能不够健壮,如果亚马逊的URL结构发生变化,或者商品ASIN码长度不全是10位,可能会导致匹配失败。你需要定期测试和维护。
  • 遵守联盟计划规则:务必仔细阅读亚马逊联盟计划(Amazon Associates)的条款。确保这种通过代理服务器自动添加tag的方式是允许的,避免违反规则导致账户被封。
  • 性能考量:此方案每次请求都会从亚马逊获取页面,可能会比较慢,并且对亚马逊的服务器造成一定压力。如果流量较大,需要考虑加入缓存机制(例如使用Redis或内存缓存一段时间内的页面),但同样需注意遵守亚马逊的条款。

💡 为什么不直接用Nginx?

你可能想知道为什么不能直接用Nginx这样的Web服务器实现。这是因为Nginx本身主要用于处理静态内容、作为反向代理[citation:5]或负载均衡器[citation:10],它不擅长直接执行业务逻辑[citation:10]。而修改HTML内容、动态添加联盟Tag这种动态内容生成[citation:9]和复杂的文本处理任务,正是Node.js(配合Express)这类应用平台/运行时环境所擅长的[citation:10]。通常的做法正是让Nginx作为反向代理,将需要特殊处理的请求转发给你的Node.js应用[citation:5]。

希望这些信息能帮你更好地理解和运行你的方案一。

时间: 2025-09-10T09:33:43


👤 用户

你好,我在使用cloudflare的works做反向代理,我想把www.amazon.co.uk的站内商品链接都加上我的推荐AssociateTrackingID,就是在商品链接后面加上“&tag=audio-media-21”,帮我修改下代码。

// Cloudflare Worker 代码 - 多域名反向代理
export default {
async fetch(request, env) {
// 域名到目标服务器的映射
const domainMappings = {
‘test.thanx.top’: ‘http://106.15.4.153:8085‘,
‘api.thanx.top’: ‘http://106.15.4.153:8086‘,
‘admin.thanx.top’: ‘http://106.15.4.153:8087‘,
‘reverse-proxy.yuebinliu.workers.dev’: ‘https://www.amazon.co.uk/s?bbn=65801031&rh=n%3A11621430031&language=en_GB&_encoding=UTF8&brr=1‘ // 测试用
};

const url = new URL(request.url);
const target = domainMappings[url.hostname];

// 如果域名未配置,返回404
if (!target) {
  return new Response('域名未配置: ' + url.hostname + '\n\n已配置的域名: ' + Object.keys(domainMappings).join(', '), { 
    status: 404,
    headers: { 'Content-Type': 'text/plain; charset=utf-8' }
  });
}

// 准备转发请求
const targetUrl = new URL(url.pathname + url.search, target);
const newHeaders = new Headers(request.headers);

// 设置代理头
newHeaders.set('X-Forwarded-Host', url.hostname);
newHeaders.set('X-Forwarded-Proto', url.protocol.replace(':', ''));
newHeaders.set('X-Real-IP', request.headers.get('cf-connecting-ip') || 'unknown');
newHeaders.delete('host'); // 删除原始host头

try {
  // 转发请求到目标服务器
  let response = await fetch(targetUrl.toString(), {
    method: request.method,
    headers: newHeaders,
    body: request.body,
    redirect: 'manual' // 手动处理重定向
  });

  // 处理重定向响应
  if ([301, 302, 303, 307, 308].includes(response.status)) {
    const location = response.headers.get('location');
    if (location && location.includes('106.15.4.153')) {
      // 替换重定向地址中的原始IP为代理域名
      const newLocation = location.replace(
        /http:\/\/106\.15\.4\.153:\d+/g, 
        `https://${url.hostname}`
      );
      const newResponse = new Response(response.body, response);
      newResponse.headers.set('location', newLocation);
      return newResponse;
    }
  }

  // 处理HTML内容,替换其中的链接
  const contentType = response.headers.get('content-type') || '';
  if (contentType.includes('text/html')) {
    let html = await response.text();
    
    // 替换所有原始服务器链接为代理域名
    html = html.replace(
      /http:\/\/106\.15\.4\.153:\d+/g,
      `https://${url.hostname}`
    );
    
    // 返回修改后的HTML
    return new Response(html, {
      status: response.status,
      headers: response.headers
    });
  }

  // 对于非HTML内容,直接返回
  return response;
  
} catch (error) {
  // 错误处理
  return new Response(`代理错误: ${error.message}\n\n目标URL: ${targetUrl.toString()}`, { 
    status: 502,
    headers: { 'Content-Type': 'text/plain; charset=utf-8' }
  });
}

}
}

时间: 2025-09-09T22:08:43


🤖 DeepSeek (deepseek-chat)

我来帮你修改代码,在Amazon商品链接后添加推荐ID。以下是修改后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Cloudflare Worker 代码 - 多域名反向代理
export default {
async fetch(request, env) {
// 域名到目标服务器的映射
const domainMappings = {
'test.thanx.top': 'http://106.15.4.153:8085',
'api.thanx.top': 'http://106.15.4.153:8086',
'admin.thanx.top': 'http://106.15.4.153:8087',
'reverse-proxy.yuebinliu.workers.dev': 'https://www.amazon.co.uk'
};

const url = new URL(request.url);
const target = domainMappings[url.hostname];

// 如果域名未配置,返回404
if (!target) {
return new Response('域名未配置: ' + url.hostname + '\n\n已配置的域名: ' + Object.keys(domainMappings).join(', '), {
status: 404,
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
}

// 准备转发请求
const targetUrl = new URL(url.pathname + url.search, target);
const newHeaders = new Headers(request.headers);

// 设置代理头
newHeaders.set('X-Forwarded-Host', url.hostname);
newHeaders.set('X-Forwarded-Proto', url.protocol.replace(':', ''));
newHeaders.set('X-Real-IP', request.headers.get('cf-connecting-ip') || 'unknown');
newHeaders.delete('host'); // 删除原始host头

try {
// 转发请求到目标服务器
let response = await fetch(targetUrl.toString(), {
method: request.method,
headers: newHeaders,
body: request.body,
redirect: 'manual' // 手动处理重定向
});

// 处理重定向响应
if ([301, 302, 303, 307, 308].includes(response.status)) {
const location = response.headers.get('location');
if (location && location.includes('106.15.4.153')) {
// 替换重定向地址中的原始IP为代理域名
const newLocation = location.replace(
/http:\/\/106\.15\.4\.153:\d+/g,
`https://${url.hostname}`
);
const newResponse = new Response(response.body, response);
newResponse.headers.set('location', newLocation);
return newResponse;
}
}

// 处理HTML内容,替换其中的链接
const contentType = response.headers.get('content-type') || '';
if (contentType.includes('text/html')) {
let html = await response.text();

// 替换所有原始服务器链接为代理域名
html = html.replace(
/http:\/\/106\.15\.4\.153:\d+/g,
`https://${url.hostname}`
);

// 在Amazon商品链接后添加推荐ID
html = html.replace(
/(https?:\/\/www\.amazon\.co\.uk\/[^"']*?\/(dp|gp\/product)\/[A-Z0-9]{10})([^"']*)/gi,
(match, baseUrl, pathType, queryString) => {
// 检查是否已经包含tag参数
if (match.includes('tag=') || match.includes('&tag=')) {
return match;
}

// 添加推荐ID
const separator = queryString.includes('?') ? '&' : '?';
return `${baseUrl}${queryString}${separator}tag=audio-media-21`;
}
);

// 返回修改后的HTML
return new Response(html, {
status: response.status,
headers: response.headers
});
}

// 对于非HTML内容,直接返回
return response;

} catch (error) {
// 错误处理
return new Response(`代理错误: ${error.message}\n\n目标URL: ${targetUrl.toString()}`, {
status: 502,
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
}
}
}

主要修改内容:

  1. 修改了Amazon的目标URL:从具体的搜索页面改为了根域名 https://www.amazon.co.uk,这样所有页面都能正常代理。

  2. 添加了推荐ID处理逻辑

    • 使用正则表达式匹配Amazon商品链接(包含 /dp//gp/product/ 的URL)
    • 检查链接是否已经包含 tag 参数,避免重复添加
    • 在链接末尾添加 &tag=audio-media-21?tag=audio-media-21(根据URL结构自动选择分隔符)
  3. 保持了原有的代理功能:包括IP地址替换、重定向处理等。

这样配置后,所有通过你的代理访问的Amazon UK商品页面都会自动加上你的推荐ID。注意这个修改只会影响HTML内容中的链接,不会影响JavaScript动态生成的链接。

时间: 2025-09-09T22:08:43


👤 用户

是这样的,如果用户通过test.thanx.top访问,那么就在我反向代理的amazon的页面里的商品链接直接添加&tag=audio-media-21,譬如“https://www.amazon.co.uk/Sexgene-Big-Thick-Dildo-Sex/dp/B0CLY3TD67/”修改成“https://www.amazon.co.uk/Sexgene-Big-Thick-Dildo-Sex/dp/B0CLY3TD67/&tag=audio-media-21”,不需要修改www.amazon.co.uk

// Cloudflare Worker 代码 - 多域名反向代理
export default {
async fetch(request, env) {
// 域名到目标服务器的映射
const domainMappings = {
‘test.thanx.top’: ‘https://www.amazon.co.uk‘,
‘api.thanx.top’: ‘http://106.15.4.153:8086‘,
‘admin.thanx.top’: ‘http://106.15.4.153:8087‘,
‘reverse-proxy.yuebinliu.workers.dev’: ‘https://www.amazon.co.uk
};

const url = new URL(request.url);
const target = domainMappings[url.hostname];

// 如果域名未配置,返回404
if (!target) {
  return new Response('域名未配置: ' + url.hostname + '\n\n已配置的域名: ' + Object.keys(domainMappings).join(', '), { 
    status: 404,
    headers: { 'Content-Type': 'text/plain; charset=utf-8' }
  });
}

// 准备转发请求
const targetUrl = new URL(url.pathname + url.search, target);
const newHeaders = new Headers(request.headers);

// 设置代理头
newHeaders.set('X-Forwarded-Host', url.hostname);
newHeaders.set('X-Forwarded-Proto', url.protocol.replace(':', ''));
newHeaders.set('X-Real-IP', request.headers.get('cf-connecting-ip') || 'unknown');
newHeaders.delete('host'); // 删除原始host头

try {
  // 转发请求到目标服务器
  let response = await fetch(targetUrl.toString(), {
    method: request.method,
    headers: newHeaders,
    body: request.body,
    redirect: 'manual' // 手动处理重定向
  });

  // 处理重定向响应
  if ([301, 302, 303, 307, 308].includes(response.status)) {
    const location = response.headers.get('location');
    if (location && location.includes('106.15.4.153')) {
      // 替换重定向地址中的原始IP为代理域名
      const newLocation = location.replace(
        /http:\/\/106\.15\.4\.153:\d+/g, 
        `https://${url.hostname}`
      );
      const newResponse = new Response(response.body, response);
      newResponse.headers.set('location', newLocation);
      return newResponse;
    }
  }

  // 处理HTML内容,替换其中的链接
  const contentType = response.headers.get('content-type') || '';
  if (contentType.includes('text/html')) {
    let html = await response.text();
    
    // 替换所有原始服务器链接为代理域名
    html = html.replace(
      /http:\/\/106\.15\.4\.153:\d+/g,
      `https://${url.hostname}`
    );
    
    // 在Amazon商品链接后添加推荐ID
    html = html.replace(
      /(https?:\/\/www\.amazon\.co\.uk\/[^"']*?\/(dp|gp\/product)\/[A-Z0-9]{10})([^"']*)/gi,
      (match, baseUrl, pathType, queryString) => {
        // 检查是否已经包含tag参数
        if (match.includes('tag=') || match.includes('&tag=')) {
          return match;
        }
        
        // 添加推荐ID
        const separator = queryString.includes('?') ? '&' : '?';
        return `${baseUrl}${queryString}${separator}tag=audio-media-21`;
      }
    );
    
    // 返回修改后的HTML
    return new Response(html, {
      status: response.status,
      headers: response.headers
    });
  }

  // 对于非HTML内容,直接返回
  return response;
  
} catch (error) {
  // 错误处理
  return new Response(`代理错误: ${error.message}\n\n目标URL: ${targetUrl.toString()}`, { 
    status: 502,
    headers: { 'Content-Type': 'text/plain; charset=utf-8' }
  });
}

}
}

时间: 2025-09-09T22:22:52


🤖 DeepSeek (deepseek-chat)

我理解你的需求了。你希望通过 test.thanx.top 访问时,在代理的Amazon页面中修改商品链接,添加你的推荐ID。我来修改代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Cloudflare Worker 代码 - 多域名反向代理
export default {
async fetch(request, env) {
// 域名到目标服务器的映射
const domainMappings = {
'test.thanx.top': 'https://www.amazon.co.uk',
'api.thanx.top': 'http://106.15.4.153:8086',
'admin.thanx.top': 'http://106.15.4.153:8087',
'reverse-proxy.yuebinliu.workers.dev': 'https://www.amazon.co.uk'
};

const url = new URL(request.url);
const target = domainMappings[url.hostname];

// 如果域名未配置,返回404
if (!target) {
return new Response('域名未配置: ' + url.hostname + '\n\n已配置的域名: ' + Object.keys(domainMappings).join(', '), {
status: 404,
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
}

// 准备转发请求
const targetUrl = new URL(url.pathname + url.search, target);
const newHeaders = new Headers(request.headers);

// 设置代理头
newHeaders.set('X-Forwarded-Host', url.hostname);
newHeaders.set('X-Forwarded-Proto', url.protocol.replace(':', ''));
newHeaders.set('X-Real-IP', request.headers.get('cf-connecting-ip') || 'unknown');
newHeaders.delete('host'); // 删除原始host头

try {
// 转发请求到目标服务器
let response = await fetch(targetUrl.toString(), {
method: request.method,
headers: newHeaders,
body: request.body,
redirect: 'manual' // 手动处理重定向
});

// 处理重定向响应
if ([301, 302, 303, 307, 308].includes(response.status)) {
const location = response.headers.get('location');
if (location) {
// 如果是Amazon的重定向,保持原样
if (location.includes('amazon.co.uk')) {
return response;
}
// 替换内部重定向地址
if (location.includes('106.15.4.153')) {
const newLocation = location.replace(
/http:\/\/106\.15\.4\.153:\d+/g,
`https://${url.hostname}`
);
const newResponse = new Response(response.body, response);
newResponse.headers.set('location', newLocation);
return newResponse;
}
}
}

// 处理HTML内容,替换其中的链接
const contentType = response.headers.get('content-type') || '';
if (contentType.includes('text/html') && url.hostname === 'test.thanx.top') {
let html = await response.text();

// 替换所有原始服务器链接为代理域名(针对内部服务)
html = html.replace(
/http:\/\/106\.15\.4\.153:\d+/g,
`https://${url.hostname}`
);

// 在Amazon商品链接后添加推荐ID(只针对test.thanx.top域名)
html = html.replace(
/(https:\/\/www\.amazon\.co\.uk\/[^"']*?\/dp\/[A-Z0-9]{10})([^"']*)/gi,
(match, baseUrl, queryString) => {
// 检查是否已经包含tag参数
if (match.includes('tag=') || match.includes('&tag=')) {
return match;
}

// 添加推荐ID - 使用正确的分隔符
const separator = queryString.includes('?') ? '&' : (queryString ? '&' : '?');
return `${baseUrl}${queryString}${separator}tag=audio-media-21`;
}
);

// 返回修改后的HTML
return new Response(html, {
status: response.status,
headers: response.headers
});
}

// 对于非HTML内容或非test域名,直接返回
return response;

} catch (error) {
// 错误处理
return new Response(`代理错误: ${error.message}\n\n目标URL: ${targetUrl.toString()}`, {
status: 502,
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
}
}
}

主要修改:

  1. 条件判断:只在 url.hostname === 'test.thanx.top' 时修改Amazon链接
  2. 链接匹配优化:使用更精确的正则表达式匹配商品链接
  3. 分隔符处理:改进分隔符逻辑,确保正确添加 &tag=audio-media-21
  4. 重定向处理:保持Amazon的重定向不变,只处理内部服务的重定向

现在当用户通过 test.thanx.top 访问时,所有Amazon商品链接都会自动添加 &tag=audio-media-21,而其他域名访问时不会修改链接。

例如:https://www.amazon.co.uk/Sexgene-Big-Thick-Dildo-Sex/dp/B0CLY3TD67/ 会被修改为 https://www.amazon.co.uk/Sexgene-Big-Thick-Dildo-Sex/dp/B0CLY3TD67/&tag=audio-media-21

时间: 2025-09-09T22:22:52


👤 用户

1,条件判断:只在 用户通过’test.thanx.top’这个地址访问 时修改Amazon链接,https://www.amazon.co.uk/Sexgene-Big-Thick-Dildo-Sex/dp/B0CLY3TD6/会被修改成https://www.amazon.co.uk/Sexgene-Big-Thick-Dildo-Sex/dp/B0CLY3TD67/&tag=audio-media-21,但不要替换.amazon.co.uk为test.thanx.top
2,判断&tag语句出错,原链接中是没有&tag的,我只是单纯的在原链接后面加上&tag=audio-media-21

时间: 2025-09-09T22:35:49


🤖 DeepSeek (deepseek-chat)

我理解了,你需要只在通过 test.thanx.top 访问时,在Amazon商品链接后面直接添加 &tag=audio-media-21,不需要替换域名。以下是修改后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Cloudflare Worker 代码 - 多域名反向代理
export default {
async fetch(request, env) {
// 域名到目标服务器的映射
const domainMappings = {
'test.thanx.top': 'https://www.amazon.co.uk',
'api.thanx.top': 'http://106.15.4.153:8086',
'admin.thanx.top': 'http://106.15.4.153:8087',
'reverse-proxy.yuebinliu.workers.dev': 'https://www.amazon.co.uk'
};

const url = new URL(request.url);
const target = domainMappings[url.hostname];

// 如果域名未配置,返回404
if (!target) {
return new Response('域名未配置: ' + url.hostname + '\n\n已配置的域名: ' + Object.keys(domainMappings).join(', '), {
status: 404,
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
}

// 准备转发请求
const targetUrl = new URL(url.pathname + url.search, target);
const newHeaders = new Headers(request.headers);

// 设置代理头
newHeaders.set('X-Forwarded-Host', url.hostname);
newHeaders.set('X-Forwarded-Proto', url.protocol.replace(':', ''));
newHeaders.set('X-Real-IP', request.headers.get('cf-connecting-ip') || 'unknown');
newHeaders.delete('host'); // 删除原始host头

try {
// 转发请求到目标服务器
let response = await fetch(targetUrl.toString(), {
method: request.method,
headers: newHeaders,
body: request.body,
redirect: 'manual' // 手动处理重定向
});

// 处理重定向响应
if ([301, 302, 303, 307, 308].includes(response.status)) {
const location = response.headers.get('location');
if (location) {
// 如果是Amazon的重定向,保持原样
if (location.includes('amazon.co.uk')) {
return response;
}
// 替换内部重定向地址
if (location.includes('106.15.4.153')) {
const newLocation = location.replace(
/http:\/\/106\.15\.4\.153:\d+/g,
`https://${url.hostname}`
);
const newResponse = new Response(response.body, response);
newResponse.headers.set('location', newLocation);
return newResponse;
}
}
}

// 处理HTML内容,替换其中的链接
const contentType = response.headers.get('content-type') || '';
if (contentType.includes('text/html')) {
let html = await response.text();

// 替换所有原始服务器链接为代理域名(针对内部服务)
html = html.replace(
/http:\/\/106\.15\.4\.153:\d+/g,
`https://${url.hostname}`
);

// 只在通过test.thanx.top访问时修改Amazon商品链接
if (url.hostname === 'test.thanx.top') {
// 匹配Amazon商品链接并添加推荐ID
html = html.replace(
/(https:\/\/www\.amazon\.co\.uk[^"']*?\/dp\/[A-Z0-9]{10}[^"']*)/gi,
(match) => {
// 检查是否已经包含tag参数,避免重复添加
if (match.includes('tag=')) {
return match;
}

// 直接在链接末尾添加&tag=audio-media-21
return match + '&tag=audio-media-21';
}
);
}

// 返回修改后的HTML
return new Response(html, {
status: response.status,
headers: response.headers
});
}

// 对于非HTML内容,直接返回
return response;

} catch (error) {
// 错误处理
return new Response(`代理错误: ${error.message}\n\n目标URL: ${targetUrl.toString()}`, {
status: 502,
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
});
}
}
}

主要修改:

  1. 精确的条件判断:只在 url.hostname === 'test.thanx.top' 时修改Amazon链接
  2. 简化链接匹配:直接匹配完整的Amazon商品链接,不拆分baseUrl和queryString
  3. 直接添加推荐ID:使用 match + '&tag=audio-media-21' 直接在原链接末尾添加
  4. 避免重复添加:检查链接是否已经包含 tag= 参数,避免重复添加

现在当用户通过 test.thanx.top 访问时:

  • https://www.amazon.co.uk/Sexgene-Big-Thick-Dildo-Sex/dp/B0CLY3TD67/ 会被修改为 https://www.amazon.co.uk/Sexgene-Big-Thick-Dildo-Sex/dp/B0CLY3TD67/&tag=audio-media-21
  • 保持 www.amazon.co.uk 域名不变
  • 其他域名访问时不会修改任何链接

时间: 2025-09-09T22:35:49


👤 用户

经过上面方法,很容易让人无误解为钓鱼网站。这样,我想在自己的web服务器上来实现上面的效果,可以实现吗?

时间: 2025-09-10T08:38:23


🤖 DeepSeek (deepseek-chat)

你说得对,直接在代理中修改Amazon链接确实容易被误认为是钓鱼网站。在你的自己的web服务器上实现这个功能是完全可以的,而且更加安全和合规。

以下是几种实现方案:

方案一:使用PHP后端处理(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
// proxy.php
$targetUrl = 'https://www.amazon.co.uk' . $_SERVER['REQUEST_URI'];

// 设置请求头
$headers = [
'User-Agent: ' . ($_SERVER['HTTP_USER_AGENT'] ?? 'Mozilla/5.0'),
'Accept: ' . ($_SERVER['HTTP_ACCEPT'] ?? 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'),
'Accept-Language: ' . ($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'en-US,en;q=0.5'),
];

// 发起请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $targetUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

$response = curl_exec($ch);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);

// 如果是HTML内容,修改商品链接
if (strpos($contentType, 'text/html') !== false) {
$response = preg_replace_callback(
'/(https:\/\/www\.amazon\.co\.uk[^"\']*?\/dp\/[A-Z0-9]{10}[^"\']*)/i',
function($matches) {
if (strpos($matches[0], 'tag=') === false) {
return $matches[0] . (strpos($matches[0], '?') ? '&' : '?') . 'tag=audio-media-21';
}
return $matches[0];
},
$response
);
}

// 输出内容
header('Content-Type: ' . $contentType);
echo $response;
?>

方案二:使用Nginx + Lua脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# nginx.conf
server {
listen 80;
server_name test.thanx.top;

location / {
# 反向代理到Amazon
proxy_pass https://www.amazon.co.uk;
proxy_set_header Host www.amazon.co.uk;
proxy_set_header User-Agent $http_user_agent;
proxy_set_header Accept $http_accept;

# 使用Lua修改响应内容
header_filter_by_lua_block {
if ngx.header.content_type and string.find(ngx.header.content_type, "text/html") then
ngx.header.content_length = nil
end
}

body_filter_by_lua_block {
if ngx.header.content_type and string.find(ngx.header.content_type, "text/html") then
local body = ngx.arg[1]
body = string.gsub(body, '(https://www%.amazon%.co%.uk[^"\']*?/dp/[A-Z0-9]+[^"\']*)', function(url)
if not string.find(url, 'tag=') then
if string.find(url, '?') then
return url .. '&tag=audio-media-21'
else
return url .. '?tag=audio-media-21'
end
end
return url
end)
ngx.arg[1] = body
end
}
}
}

方案三:使用Node.js Express

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// server.js
const express = require('express');
const axios = require('axios');
const app = express();

app.use(async (req, res) => {
try {
const targetUrl = `https://www.amazon.co.uk${req.url}`;

const response = await axios.get(targetUrl, {
headers: {
'User-Agent': req.headers['user-agent'],
'Accept': req.headers['accept'],
'Accept-Language': req.headers['accept-language']
},
responseType: 'arraybuffer'
});

let content = response.data.toString();
const contentType = response.headers['content-type'];

if (contentType.includes('text/html')) {
content = content.replace(
/(https:\/\/www\.amazon\.co\.uk[^"']*?\/dp\/[A-Z0-9]{10}[^"']*)/gi,
(match) => {
if (!match.includes('tag=')) {
return match + (match.includes('?') ? '&' : '?') + 'tag=audio-media-21';
}
return match;
}
);
}

res.set(response.headers);
res.send(content);
} catch (error) {
res.status(500).send('Error: ' + error.message);
}
});

app.listen(3000, () => {
console.log('Server running on port 3000');
});

安装说明

PHP方案:

  1. 安装PHP和cURL扩展
  2. 将proxy.php上传到你的web服务器
  3. 配置Nginx/Apache指向这个文件

Node.js方案:

1
2
3
npm init -y
npm install express axios
node server.js

优势对比

方案 优点 缺点
PHP 部署简单,兼容性好 性能相对较低
Nginx+Lua 高性能,原生支持 需要安装Lua模块
Node.js 灵活,现代技术栈 需要Node.js环境

推荐使用PHP方案,因为它最简单且兼容性最好,只需要基本的PHP环境即可运行。

这样实现既避免了被误认为钓鱼网站的风险,又能在你自己的服务器上实现相同的功能。

时间: 2025-09-10T08:38:23


👤 用户

没关系,node.js和python环境都没有问题的,简单安装下就好了

时间: 2025-09-10T09:03:16


🤖 DeepSeek (deepseek-chat)

好的,既然你有Node.js和Python环境,那我给你提供这两个版本的实现方案:

方案一:Node.js + Express 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// server.js
const express = require('express');
const axios = require('axios');
const { URL } = require('url');
const app = express();

// 处理所有请求
app.use(async (req, res) => {
try {
const targetUrl = `https://www.amazon.co.uk${req.originalUrl}`;
console.log('Proxying:', targetUrl);

// 转发请求到Amazon
const response = await axios({
method: req.method,
url: targetUrl,
headers: {
'User-Agent': req.headers['user-agent'] || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': req.headers['accept'] || 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': req.headers['accept-language'] || 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
},
responseType: 'arraybuffer',
validateStatus: null, // 接受所有状态码
});

let content = response.data;
const contentType = response.headers['content-type'];

// 只在HTML内容中修改商品链接
if (contentType && contentType.includes('text/html')) {
content = content.toString();

// 匹配Amazon商品链接并添加推荐ID
content = content.replace(
/(https:\/\/www\.amazon\.co\.uk(\/[^"'\s]*?\/dp\/[A-Z0-9]{10}[^"'\s]*))/gi,
(match, url) => {
// 检查是否已经包含tag参数
if (url.includes('tag=')) {
return match;
}

// 添加推荐ID
const separator = url.includes('?') ? '&' : '?';
return match.replace(url, url + separator + 'tag=audio-media-21');
}
);
}

// 设置响应头
Object.entries(response.headers).forEach(([key, value]) => {
if (key.toLowerCase() !== 'content-length') {
res.setHeader(key, value);
}
});

res.status(response.status).send(content);

} catch (error) {
console.error('Proxy error:', error.message);
res.status(500).send(`Proxy error: ${error.message}`);
}
});

// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Amazon proxy server running on port ${PORT}`);
console.log(`Access via: http://localhost:${PORT}`);
});

// package.json 依赖
// {
// "name": "amazon-proxy",
// "version": "1.0.0",
// "dependencies": {
// "express": "^4.18.2",
// "axios": "^1.6.0"
// }
// }

安装运行:

1
2
3
npm init -y
npm install express axios
node server.js

方案二:Python + Flask 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# app.py
from flask import Flask, request, Response
import requests
import re
from urllib.parse import urljoin

app = Flask(__name__)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def proxy(path):
try:
# 构建目标URL
target_url = urljoin('https://www.amazon.co.uk/', path)
if request.query_string:
target_url += '?' + request.query_string.decode()

print(f'Proxying: {target_url}')

# 转发请求头
headers = {
'User-Agent': request.headers.get('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'),
'Accept': request.headers.get('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'),
'Accept-Language': request.headers.get('Accept-Language', 'en-US,en;q=0.9'),
'Accept-Encoding': 'gzip, deflate, br',
}

# 发送请求到Amazon
response = requests.request(
method=request.method,
url=target_url,
headers=headers,
data=request.get_data(),
cookies=request.cookies,
allow_redirects=False,
stream=True
)

# 处理响应
content_type = response.headers.get('Content-Type', '')

if 'text/html' in content_type:
# 处理HTML内容
content = response.content.decode('utf-8', errors='ignore')

# 修改商品链接
def add_affiliate_tag(match):
url = match.group(1)
if 'tag=' in url:
return match.group(0)

separator = '?' if '?' not in url else '&'
return match.group(0).replace(url, url + separator + 'tag=audio-media-21')

# 匹配Amazon商品链接
content = re.sub(
r'(https://www\.amazon\.co\.uk(/[^"\'\s]*?/dp/[A-Z0-9]{10}[^"\'\s]*))',
add_affiliate_tag,
content,
flags=re.IGNORECASE
)

# 创建响应
flask_response = Response(content, status=response.status_code)
else:
# 非HTML内容直接转发
flask_response = Response(response.iter_content(chunk_size=1024), status=response.status_code)

# 复制响应头
for key, value in response.headers.items():
if key.lower() not in ['content-length', 'transfer-encoding']:
flask_response.headers[key] = value

return flask_response

except Exception as e:
print(f'Error: {e}')
return f'Proxy error: {e}', 500

if __name__ == '__main__':
app.run(host='0.0.0.0', port=3000, debug=True)

# requirements.txt
# flask==2.3.3
# requests==2.31.0

安装运行:

1
2
pip install flask requests
python app.py

方案三:使用 http-proxy-middleware(更专业的Node.js方案)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// proxy-server.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const cheerio = require('cheerio');
const { Transform } = require('stream');

const app = express();

// 创建转换流来处理HTML内容
class HtmlTransformStream extends Transform {
_transform(chunk, encoding, callback) {
let html = chunk.toString();

// 修改Amazon商品链接
html = html.replace(
/(https:\/\/www\.amazon\.co\..uk(\/[^"'\s]*?\/dp\/[A-Z0-9]{10}[^"'\s]*))/gi,
(match, url) => {
if (url.includes('tag=')) return match;
const separator = url.includes('?') ? '&' : '?';
return match.replace(url, url + separator + 'tag=audio-media-21');
}
);

this.push(html);
callback();
}
}

// 配置代理中间件
const proxy = createProxyMiddleware({
target: 'https://www.amazon.co.uk',
changeOrigin: true,
selfHandleResponse: true,
onProxyRes: (proxyRes, req, res) => {
const contentType = proxyRes.headers['content-type'];

if (contentType && contentType.includes('text/html')) {
// 处理HTML响应
const transformStream = new HtmlTransformStream();

// 移除content-length头
delete proxyRes.headers['content-length'];

// 设置响应头
Object.keys(proxyRes.headers).forEach(key => {
res.setHeader(key, proxyRes.headers[key]);
});

proxyRes.pipe(transformStream).pipe(res);
} else {
// 非HTML内容直接转发
proxyRes.pipe(res);
}
},
onError: (err, req, res) => {
console.error('Proxy error:', err);
res.status(500).send('Proxy error');
}
});

// 使用代理中间件
app.use('/', proxy);

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Proxy server running on port ${PORT}`);
});

安装运行:

1
2
npm install express http-proxy-middleware cheerio
node proxy-server.js

推荐使用

推荐方案一(Express + Axios),因为它:

  1. 代码简洁易懂
  2. 功能完整
  3. 错误处理完善
  4. 性能足够

运行后访问 http://你的服务器IP:3000 即可看到效果,所有Amazon商品链接都会自动添加你的推荐ID。

时间: 2025-09-10T09:03:16


👤 用户

这个方案一使用的什么web服务器?

时间: 2025-09-10T09:33:43


🤖 DeepSeek (deepseek-chat)

根据你提供的”方案一”代码,它使用的是 Node.js 的 Express 框架 来构建的 Web 服务器。这是一个非常流行和灵活的 JavaScript 服务器框架。

🖥️ 核心组件与工作原理

方案一主要依赖以下核心库:

核心库 用途 版本建议
Express 作为Web应用框架,处理路由、中间件和HTTP请求/响应[citation:8] ^4.18.2
Axios 用于向亚马逊服务器发起HTTP请求,获取原始页面内容 ^1.6.0
Node.js 内置模块 (如 http, url) 提供基础的HTTP服务器和URL解析能力[citation:8] -

其工作原理如下图所示,可以看到一个请求是如何被处理的:

1
2
3
4
5
6
7
flowchart TD
A[用户访问你的服务器] --> B[Express 接收请求]
B --> C[Axios 向亚马逊请求原始页面]
C --> D{是否是HTML?}
D -- 是 --> E[正则匹配商品链接]
E --> F[添加联盟Tag后返回]
D -- 否 --> G[直接返回原始内容]

⚙️ 部署注意事项

要让这个服务器稳定运行,你需要:

  1. 安装依赖:在放代码的目录下运行 npm install express axios
  2. 启动服务:运行 node server.js。生产环境建议使用 PM2 等进程管理器来守护进程和实现零停机重启。
  3. 反向代理(可选但推荐):虽然你的代码本身是一个功能完整的Web服务器,但通常在生产环境中,强烈建议 在其前面搭配 Nginx[citation:5] 或 Caddy 这样的专业Web服务器作为反向代理。这样做能带来很多好处:
    • 提升性能:Nginx可以高效处理静态文件(如图片、CSS、JS)、SSL加密和解密,减轻Node.js进程的负担[citation:5]。
    • 增强安全性:隐藏后端Node.js服务器,提供额外的安全层。
    • 提高可靠性:可以做负载均衡,或者在你的Node.js应用意外崩溃时提供更优雅的错误处理。

一个简单的Nginx配置示例(/etc/nginx/sites-available/your-site)可能看起来像这样[citation:5]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
listen 80;
server_name your-domain.com; # 你的域名

location / {
proxy_pass http://localhost:3000; # 转发给本地运行的Node.js应用
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}

记得配置后通过 sudo nginx -t 测试配置,并用 sudo systemctl reload nginx 重载Nginx。

⚠️ 重要提醒

  • 正则表达式的局限性:代码中通过正则表达式匹配商品链接(匹配包含 /dp/ 后接10位字母数字的模式)并添加 &tag=audio-media-21。这种方式可能不够健壮,如果亚马逊的URL结构发生变化,或者商品ASIN码长度不全是10位,可能会导致匹配失败。你需要定期测试和维护。
  • 遵守联盟计划规则:务必仔细阅读亚马逊联盟计划(Amazon Associates)的条款。确保这种通过代理服务器自动添加tag的方式是允许的,避免违反规则导致账户被封。
  • 性能考量:此方案每次请求都会从亚马逊获取页面,可能会比较慢,并且对亚马逊的服务器造成一定压力。如果流量较大,需要考虑加入缓存机制(例如使用Redis或内存缓存一段时间内的页面),但同样需注意遵守亚马逊的条款。

💡 为什么不直接用Nginx?

你可能想知道为什么不能直接用Nginx这样的Web服务器实现。这是因为Nginx本身主要用于处理静态内容、作为反向代理[citation:5]或负载均衡器[citation:10],它不擅长直接执行业务逻辑[citation:10]。而修改HTML内容、动态添加联盟Tag这种动态内容生成[citation:9]和复杂的文本处理任务,正是Node.js(配合Express)这类应用平台/运行时环境所擅长的[citation:10]。通常的做法正是让Nginx作为反向代理,将需要特殊处理的请求转发给你的Node.js应用[citation:5]。

希望这些信息能帮你更好地理解和运行你的方案一。

时间: 2025-09-10T09:33:43



对话统计

  • 消息总数: 12 条
  • 处理状态: 成功转换