0


如何内网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 权限创建用户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()

至此高德地图集成完成。

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

  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动态域名解析解决该问题。
标签: nginx 运维 前端

本文转载自: https://blog.csdn.net/w597412819/article/details/134598143
版权归原作者 w597412819 所有, 如有侵权,请联系我们删除。

“如何内网nginx正向代理外网,并实现高德地图”的评论:

还没有评论