项目背景
近期遇到一个内网实现高德地图的需求,初步分析之后,需要解决两个问题,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 权限创建用户nginxuseradd nginx
passwd nginx
#进入nginx用户目录,新建upload目录,上传nginx包和sub_filter包cd /home/nginx
mkdir-p upload
rz -ry#解压nginxcd /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_filtercd nginx-1.22.1
./configure --with-http_sub_module --add-module=/home/nginx/upload/ngx_http_substitutions_filter_module
#安装 默认安装在/usr/local/nginxmake&&makeinstall#执行后再给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 500502503504 /50x.html;
location = /50x.html {
root html;}}}
2、代理服务器B,nginx搭建:
#root 权限创建用户nginxuseradd nginx
passwd nginx
#进入nginx用户目录,新建upload目录,上传nginx包和正向代理模块包、ssl包cd /home/nginx
mkdir-p upload
rz -ry#解压nginxcd /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/nginxmake&&makeinstall#执行后再给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.comcurl--proxy127.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。
<template><div id="container"></div></template>
第三步:
设置地图容器样式
<style scoped>#container{
padding:0px;
margin: 0px;
width: 100%;
height: 800px;}</style>
第四步:
在 MapContainer.vue文件中初始化地图
<template><div id="container"></div></template><script>import AMapLoader from "@amap/amap-jsapi-loader";
window._AMapSecurityConfig ={
securityJsCode: "「你申请的安全密钥」",
};export default {
name: "map-view",
mounted(){
this.initAMap();},
unmounted(){
this.map?.destroy();},
methods: {initAMap(){
AMapLoader.load({
key: "", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then((AMap)=>{
this.map = new AMap.Map("container", {
// 设置地图容器id
viewMode: "3D", // 是否为3D地图模式
zoom: 11, // 初始化地图级别
center: [116.397428, 39.90923], // 初始化地图中心点位置
});})
.catch((e)=>{
console.log(e);});},
},
};</script><style scoped>#container {
width: 100%;
height: 800px;}</style>
注意:因为我的主项目对define方法有定义,和JSAPI代码有冲突,导致JSAPI被请求后,无法正常初始化,所以在执行AMapLoader.load之前对window.define做了重新赋值,如下:
window.defineInit= window.define
window.define= null
#TODO 执行AMapLoader.load,执行完成之后,重新赋值definewindow.define= window.defineInit
window.defineInit= null
因为是loader方式,所以在调用之前,要全局拦截js,转发请求到代理服务器
functionhookScript(){
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]}elseif(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动态域名解析解决该问题。
版权归原作者 w597412819 所有, 如有侵权,请联系我们删除。