如何内网nginx正向代理外网,并实现高德地图

项目背景
近期遇到一个内网实现高德地图的需求,初步分析之后,需要解决两个问题,1、nginx正向代理访问高德地图相关域名;2、创建高德地图实例,并实现相关功能

一、先说nginx这块,一台网关服务器A,放静态资源包,一台代理服务器B,访问外网,因为是内网应用,使用的都是离线包,包如下

  1. nginx-1.22.1.tar.gz 提取码 x7qv
  2. ngx_http_proxy_connect_module-master.zip 提取码 exyq
  3. ngx_http_substitutions_filter_module-master.zip 提取码 sit9
  4. 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。

<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,执行完成之后,重新赋值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()

至此高德地图集成完成。

总结:
整个过程遇到一下几个问题:

  1. 加载JSAPI后,无法调起后续请求,也无任何报错,因为内网开发,一开始以为网络问题,后来网络开通后,还是无法调起,经过源码打断点发现,内部JS 因window.define已定义,导致初始化终止,通过重置window.define方法解决JSAPI不完全调用问题;
  2. JSAPI会内部调用其他域名的请求,对于这个问题,一开始使用Object.getOwnPropertyDescriptor在原型上去全局拦截script、image、xhr等,进而重写url,但是项目里对fetch请求方式做了定义,无法很好的拦截jsapi发出的fetch请求,最后除了“webapi.amap.com”,其他的域名通过sub_filter进行全文替换,把域名替换成代理服务的地址;
  3. nginx的dns缓存问题,经常服务启动后,长时间不访问,代理就报错502、504等连接超时问题,后通过proxy_pass动态域名解析解决该问题。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值