最近需要部署一套分内外网的项目。各位大佬都知道,在内网环境中,我们是不能随便访问外网的,所以这个项目用到的高德地图web服务就歇菜了😖

由于项目时间紧凑,所以我们通过简单的方法实现内网服务访问外网的GIS服务

分析

项目中使用高德地图一般有两种方式,直接script脚本加载或者使用@amap/amap-jsapi-loader,两种方式都是通过访问 https://webapi.amap.com/maps,来获取js api文件,所以我们将会通过这个文件追踪之后访问链接

通过浏览器F12 Network和Sources分析能得到它主要调用以下链接:

  • webapi.amap.com && http://webapi.amap.com && https://webapi.amap.com
  • restapi.amap.com
  • a.amap.com
  • vdata.amap.com
  • vdata01.amap.com && vdata02.amap.com && vdata03.amap.com && vdata04.amap.com
  • webst01.is.autonavi.com && webst02.is.autonavi.com && webst03.is.autonavi.com && webst04.is.autonavi.com
  • wprd01.is.autonavi.com && wprd02.is.autonavi.com && wprd03.is.autonavi.com && wprd04.is.autonavi.com

Nginx配置

为了让我们获取到的js api通过代理去访问,我们需要用到Nginxsub_filter模块,安装方法请看

先把上面提到的链接做个代理,能正常在浏览器访问证明代理成功

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
location /webAmap/ {
proxy_pass https://webapi.amap.com/;
}
location /restAmap/ {
proxy_pass https://restapi.amap.com/;
}
location /amap/ {
proxy_pass https://a.amap.com/;
}
location /vdata/ {
proxy_pass https://vdata.amap.com/;
}
location /vdata01/ {
proxy_pass https://vdata01.amap.com/;
}
location /vdata02/ {
proxy_pass https://vdata02.amap.com/;
}
location /vdata03/ {
proxy_pass https://vdata03.amap.com/;
}
location /vdata04/ {
proxy_pass https://vdata04.amap.com/;
}
location /webst01/ {
proxy_pass https://webst01.is.autonavi.com/;
}
location /webst02/ {
proxy_pass https://webst02.is.autonavi.com/;
}
location /webst03/ {
proxy_pass https://webst03.is.autonavi.com/;
}
location /webst04/ {
proxy_pass https://webst04.is.autonavi.com/;
}
location /wprd01/ {
proxy_pass https://wprd01.is.autonavi.com/;
}
location /wprd02/ {
proxy_pass https://wprd02.is.autonavi.com/;
}
location /wprd03/ {
proxy_pass https://wprd03.is.autonavi.com/;
}
location /wprd04/ {
proxy_pass https://wprd04.is.autonavi.com/;
}

接下来使用sub_filter模块增加配置替换js文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location /maps {
proxy_set_header Accept-Encoding ""; # 返回的js文件不经过GZip压缩,方便替换内容
proxy_pass https://webapi.amap.com/maps;
sub_filter_types *; # 文件类型 *为所有
sub_filter_once off; # 是否只替换一次 默认on 这里改为off
sub_filter 'webapi.amap.com' '代理地址/webAmap'; # sub_filter '原来内容' '替换内容'
sub_filter 'http://webapi.amap.com' 'https://代理地址/webAmap';
sub_filter 'https://webapi.amap.com' 'https://代理地址/webAmap';
sub_filter 'https://restapi.amap.com' 'https://代理地址/restAmap';
sub_filter 'a.amap.com' 'dev.bonahl.com/amap';
sub_filter 'vdata.amap.com' '代理地址/vdata';
sub_filter '{vdata,vdata01,vdata02,vdata03,vdata04}.amap.com' '代理地址/{vdata,vdata01,vdata02,vdata03,vdata04}';
sub_filter 'webst0{1,2,3,4}.is.autonavi.com' '代理地址/webst0{1,2,3,4}';
sub_filter 'wprd0{1,2,3,4}.is.autonavi.com' '代理地址/wprd0{1,2,3,4}';
}

这里因为我的域名是使用https的,但是他有一个marker的icon文件使用http,所以我还需要加一个配置,把所有的http请求重写成https

1
2
3
4
5
server {
listen 80;
server_name 代理地址;
rewrite ^/(.*)$ https://代理地址/$1 permanent;
}

项目修改

  • 脚本引入方式
    1
    <script type="text/javascript" src="https://代理地址/maps?v=2.0&key=您申请的key值"></script>
  • vue中通过@amap/amap-jsapi-loader使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    hookSrcipt() {
    const mapsUrl = 'https://webapi.amap.com/maps'
    const webapiHttpsUrl = 'https://webapi.amap.com'
    const restApiUrl = 'https://restapi.amap.com'
    const property = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, 'src')
    const nativeSet = property.set

    function customiseSrcSet(url) {
    console.log('before', url)
    if (url.toString().search(mapsUrl) !== -1) {
    url = 'https://代理地址/maps' + url.split(mapsUrl)[1]
    } else if (url.toString().search(webapiHttpsUrl) !== -1) {
    url = 'https://代理地址/webAmap' + url.split(webapiHttpsUrl)[1]
    } else if (url.toString().search(restApiUrl) !== -1) {
    url = 'https://代理地址/restAmap' + url.split(restApiUrl)[1]
    }
    console.log('end', url)
    nativeSet.call(this, url)
    }
    Object.defineProperty(HTMLScriptElement.prototype, 'src', {
    set: customiseSrcSet
    })
    }

结语

到此代理完成,打开F12强刷一下可以看到请求地址已经改成代理地址,该笔记记录为高德js地图2.0版本代理方法,参考这篇文件1.4.15版本的代理方法