forked from naturalatlas/tilestrata-proxy
/
index.js
117 lines (103 loc) · 3.74 KB
/
index.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
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
110
111
112
113
114
115
116
117
var request = require('request');
var zlib = require('zlib');
function template(str, data) {
return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
var value = data[key];
if (value === undefined) {
throw new Error('No value provided for variable ' + str);
} else if (typeof value === 'function') {
value = value(data);
}
return value;
});
}
module.exports = function(options) {
if (typeof options === 'string') options = {uri: options};
if (!options.uri) throw new Error('Missing proxy "uri" parameter');
var uri = options.uri;
var decompress = options.decompress || 'always';
var subdomains = options.subdomains || 'abc';
var usesSubdomainReplacement = typeof uri === 'string' && uri.indexOf('{s}') > -1;
var headers = decompress === 'always' ? {'Accept-Encoding': 'gzip, deflate'} : {};
for (var k in options.headers) {
if (options.headers.hasOwnProperty(k)) {
headers[k] = options.headers[k];
}
}
return {
name: 'proxy',
serve: function(server, req, callback) {
// use the client's accept-encoding if we want decompression
// behavior to be determined by client capabilities
var finalRequestHeaders = headers;
if (decompress === 'client') {
var finalRequestHeaders = {};
for (var k in headers) {
if (headers.hasOwnProperty(k)) {
finalRequestHeaders[k] = headers[k];
}
}
finalRequestHeaders['Accept-Encoding'] = req.headers['accept-encoding'];
}
//防止请求被禁止
finalRequestHeaders['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4115.5 Safari/537.36';
var requestURI;
if (typeof uri === 'function') {
requestURI = uri(req);
} else {
requestURI = uri;
if (usesSubdomainReplacement) {
var sudomainIndex = Math.abs(req.x + req.y) % subdomains.length;
var subdomain = subdomains[sudomainIndex];
requestURI = requestURI.replace('{s}', subdomain);
}
requestURI = template(requestURI, req);
}
if (!requestURI) {
var error = new Error('No proxy url defined for this tile');
error.statusCode = 404;
return callback(error);
}
var options = {
headers: finalRequestHeaders,
uri: requestURI,
encoding: null // we want a buffer, not a string
};
request(options, function onResponse(err, resp, body) {
if (err) return callback(err);
// don't accept anything but a 200 OK
if (resp.statusCode !== 200) {
var httpError = new Error('Received non-200 status from upstream (' + resp.statusCode + ')');
httpError.statusCode = resp.statusCode;
return callback(httpError);
}
// detect content encoding
var contentEncoding = (resp.headers['content-encoding'] || '').toLowerCase();
if (!contentEncoding) {
if (body && body[0] === 0x1F && body[1] === 0x8B) contentEncoding = 'gzip';
if (body && body[0] === 0x78 && body[1] === 0x9C) contentEncoding = 'deflate';
}
// should we attempt decompression?
var shouldDecompress = false;
if (contentEncoding === 'gzip' || contentEncoding === 'deflate') {
shouldDecompress = decompress === 'always';
if (decompress === 'client') {
var clientSupportedEncodings = (req.headers['accept-encoding'] || '').trim().toLowerCase().split(/\s*,\s*/);
shouldDecompress = clientSupportedEncodings.indexOf(contentEncoding) === -1;
}
}
// decompress body
if (shouldDecompress) {
var fn = contentEncoding === 'gzip' ? 'gunzip' : 'inflate';
return zlib[fn](body, function(err, data) {
if (err) return callback(err);
delete resp.headers['content-encoding'];
delete resp.headers['content-length'];
callback(null, data, resp.headers);
});
}
callback(null, body, resp.headers);
});
}
};
};