项目背景
近期遇到一个内网实现高德地图的需求,初步分析之后,需要解决两个问题,1、nginx正向代理访问高德地图相关域名;2、创建高德地图实例,并实现相关功能
一、先说nginx这块,一台网关服务器A,放静态资源包,一台代理服务器B,访问外网,因为是内网应用,使用的都是离线包,包如下
- nginx-1.22.1.tar.gz 提取码 x7qv
- ngx_http_proxy_connect_module-master.zip 提取码 exyq
- ngx_http_substitutions_filter_module-master.zip 提取码 sit9
- openssl-1.1.1w.tar.gz 提取码 d9em
1、网关服务器A,nginx搭建:
#root 权限创建用户nginx useradd nginx passwd nginx #进入nginx用户目录,新建upload目录,上传nginx包和sub_filter包 cd /home/nginx mkdir -p upload rz -ry #解压nginx cd /home/nginx/upload tar -zxvf nginx-1.22.1.tar.gz #解压sub_filter模块包 unzip ngx_http_substitutions_filter_module-master.zip mv ngx_http_substitutions_filter_module-master ngx_http_substitutions_filter_module #编译 sub_filter cd nginx-1.22.1 ./configure --with-http_sub_module --add-module=/home/nginx/upload/ngx_http_substitutions_filter_module #安装 默认安装在/usr/local/nginx make && make install #执行后再给nginx赋权 chown -R nginx:nginx /usr/local/nginx /home/nginx/upload #修改nginx配置文件 启动nginx
A服务器nginx配置如下:
worker_processes auto; error_log logs/error.log error; pid logs/nginx.pid; worker_rlimit_nofile 16384; events { use epoll; worker_connections 16384; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #gzip on; upstream backend { server "代理服务器B的ip" } server { listen 8080; server_name localhost; location / { root html; index index.html index.htm; } #代理获取jsapi文件并修改文件内容 location /mapsUrl/ { proxy_set_header Accept-Encoding ""; set $proxyip "服务器A的ip:8080"; #注意这里的proxy_pass 我用动态的有时候reload时不生效,可以直接用静态的proxy_pass http://代理服务器ip:8080/maps; proxy_pass http://服务器A的ip:8080/maps; sub_filter_types *; sub_filter_once off; sub_filter 'https' 'http'; sub_filter 'webapi.amap.com' '$proxyip/webapi'; sub_filter 'restapi.amap.com' '$proxyip/restapi'; sub_filter 'vdata.amap.com' '$proxyip/vdata'; sub_filter 'a.amap.com' '$proxyip/aUrl'; sub_filter 'vdata0{1,2,3,4}.amap.com' '$proxyip/vdata0{1,2,3,4}'; sub_filter '{vdata,vdata01,vdata02,vdata03,vdata04}.amap.com' '$proxyip/{vdata,vdata01,vdata02,vdata03,vdata04}'; sub_filter 'wprd0{1,2,3,4}.is.autonavi.com' '$proxyip/wprd0{1,2,3,4}'; sub_filter 'webrd0{1,2,3,4}.is.autonavi.com' '$proxyip/webrd0{1,2,3,4}'; } location /maps { proxy_pass http://$backend; } location ~* ^/webapi(.*) { proxy_pass http://$backend; } location ~* ^/restapi(.*) { proxy_pass http://$backend; } location /vdata { proxy_pass http://$backend; } location ~* ^/aUrl(.*) { proxy_pass http://$backend; } location ~* ^/wprd0(\d*)/(.*) { proxy_pass http://$backend; } location ~* ^/webrd0(\d*)/(.*) { proxy_pass http://$backend; } location ~* ^/vdata0(\d*)/(.*) { proxy_pass http://$backend; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
2、代理服务器B,nginx搭建:
#root 权限创建用户nginx useradd nginx passwd nginx #进入nginx用户目录,新建upload目录,上传nginx包和正向代理模块包、ssl包 cd /home/nginx mkdir -p upload rz -ry #解压nginx cd /home/nginx/upload tar -zxvf nginx-1.22.1.tar.gz #解压openssl-1.1.1w.tar.gz #解压正向代理模块包 unzip ngx_http_proxy_connect_module-master.zip mv ngx_http_proxy_connect_module-master ngx_http_proxy_connect_module #查看 正向代理模块包proxy_connect_rewrite_102101.patch位置(因为nginx版本问题,对代理模块的版本有要求) cd nginx-1.22.1 ll ../ngx_http_proxy_connect_module/patch #导入模块 patch -p1 < /home/nginx/upload/ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_102101.patch #编译 proxy 、 openssl ./configure --add-module=/home/nginx/upload/ngx_http_proxy_connect_module --with-http_ssl_module --with-openssl=/home/nginx/upload/openssl-1.1.1w #安装 默认安装在/usr/local/nginx make && make install #执行后再给nginx赋权 #代理服务器只开通了80端口,无法nginx启动,只能root权限启动 chown -R nginx:nginx /usr/local/nginx /home/nginx/upload
B代理服务器nginx配置如下:
worker_processes auto; error_log logs/error.log error; pid logs/nginx.pid; worker_rlimit_nofile 16384; events { use epoll; worker_connections 16384; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #gzip on; proxy_connect_timeout 5; proxy_read_timeout 60; proxy_send_timeout 5; proxy_buffer_size 16k; proxy_buffers 4 64k; proxy_busy_buffers_size 128k; proxy_temp_file_write_size 128k; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } location /maps { resolver 114.114.114.114; set $backend "webapi.amap.com"; proxy_pass https://$backend; } location ~* ^/aUrl(.*) { resolver 114.114.114.114; set $backend "a.amap.com"; proxy_pass https://$backend$1$is_args$args; } location ~* ^/restapi(.*) { resolver 114.114.114.114; set $backend "restapi.amap.com"; proxy_pass https://$backend$1$is_args$args; } location ~* ^/webapi(.*) { resolver 114.114.114.114; set $backend "webapi.amap.com"; proxy_pass https://$backend$1$is_args$args; } location ~* ^/vdata0(\d*)/(.*) { resolver 114.114.114.114; set $backend "amap.com"; proxy_pass https://vdata0$1.$backend/$2$is_args$args; } location ~* ^/vdata(.*) { resolver 114.114.114.114; set $backend "vdata.amap.com"; proxy_pass https://$backend$1$is_args$args; } location ~* ^/wprd0(\d*)/(.*) { resolver 114.114.114.114; set $backend "is.autonavi.com"; proxy_pass https://wprd0$1.$backend/$2$is_args$args; } location ~* ^/webrd0(\d*)/(.*) { resolver 114.114.114.114; set $backend "is.autonavi.com"; proxy_pass https://webrd0$1.$backend/$2$is_args$args; } } }
到此nginx安装完成
二、配置代理服务器的dns
我们网络部门给开的dns地址是114.114.114.114,需要在代理服务器配置一下
vim /etc/resolv.conf #添加dns 114.114.114.114
三、重启nginx,验证代理是否成功
这里需要注意下,对应的外网域名可能会变化,我目前遇到的域名有以下几个:webapi.amap.com、restapi.amap.com、vdata.amap.com、a.amap.com、vdata0{1,2,3,4}.amap.com、webrd0{1,2,3,4}.is.autonavi.com、wprd0{1,2,3,4}.is.autonavi.com
具体需要开通哪些域名,根据项目需求。
在代理服务器B,进行以下操作,进行验证:
#检验配置是否正确 ./nginx -t #重启nginx ./nginx -s reload #验证是否可以访问域名webapi.amap.com curl --proxy 127.0.0.1:80 http://webapi.amap.com/maps
至此正向代理服务搭建完成。
四、参考官网JSAPI集成高德地图
官网地址如下:
https://lbs.amap.com/api/javascript-api-v2/guide/abc/jscode
集成地图这块比较简单,按照官网的步骤就可以实现,这里只是大概说下实现步骤和遇到的问题:
第一步:
按 NPM 方式安装使用 Loader ,如果是内网环境,现在外网安装,再把包拷贝到内网使用
npm i @amap/amap-jsapi-loader --save
第二步:
在项目中新建 MapContainer.vue 文件,用作地图组件,在 MapContainer.vue 地图组件中创建 div 标签作为地图容器 ,并设置地图容器的 id 属性为 container。
第三步:
设置地图容器样式
第四步:
在 MapContainer.vue文件中初始化地图
注意:因为我的主项目对define方法有定义,和JSAPI代码有冲突,导致JSAPI被请求后,无法正常初始化,所以在执行AMapLoader.load之前对window.define做了重新赋值,如下:
window.defineInit= window.define window.define= null #TODO 执行AMapLoader.load,执行完成之后,重新赋值define window.define= window.defineInit window.defineInit= null
因为是loader方式,所以在调用之前,要全局拦截js,转发请求到代理服务器
function hookScript() { const $url = '网关服务器A的IP:8080' const maps = 'https://webapi.amap.com/maps' const webapi = 'https://webapi.amap.com' const property = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, 'src') const nativeSet = property.set function customiseSrcSet(url){ if(url.toString().search(maps) !== -1){ url = $url + '/mapsUrl' + url.split(maps)[1] } else if (url.toString().search(webapi) !== -1){ url = $url + '/webapi' + url.split(webapi)[1] } nativeSet.call(this, url) } Object.defineProperty(HTMLScriptElement.propertype, 'src', { set: customiseSrcSet } } hookScript()
至此高德地图集成完成。
总结:
整个过程遇到一下几个问题:
- 加载JSAPI后,无法调起后续请求,也无任何报错,因为内网开发,一开始以为网络问题,后来网络开通后,还是无法调起,经过源码打断点发现,内部JS 因window.define已定义,导致初始化终止,通过重置window.define方法解决JSAPI不完全调用问题;
- JSAPI会内部调用其他域名的请求,对于这个问题,一开始使用Object.getOwnPropertyDescriptor在原型上去全局拦截script、image、xhr等,进而重写url,但是项目里对fetch请求方式做了定义,无法很好的拦截jsapi发出的fetch请求,最后除了“webapi.amap.com”,其他的域名通过sub_filter进行全文替换,把域名替换成代理服务的地址;
- nginx的dns缓存问题,经常服务启动后,长时间不访问,代理就报错502、504等连接超时问题,后通过proxy_pass动态域名解析解决该问题。
还没有评论,来说两句吧...