GoogleMapAPI 国内反代部署方案

By | 2018年7月10日

本文记录下自己在NiceBing网站中使用到的谷歌地图服务是如何自己部署反代的。这里仅介绍如何部署反代,Google Map API接口本身的使用方式会另外介绍,您也可以去官方查看Map开发文档

通过反代可以在大陆区域顺畅使用Google Map的API接口,无需梯子!当然,如果您自己部署,需要一台国外的服务器。

本文适合有Nginx配置经验的老手阅读,新手请先了解Nginx的配置文件(location、Https等配置).

在使用Map javascript API时会先引用一个google的map js文件:

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></script>

这个maps.googleapis.com域名在国内自然是不能访问的,不过官方针对中国地区,提供了cn版的域名:

http://maps.google.cn

不幸的是,虽然maps.google.cn是可以访问的,但是js内部还有很多资源链接依然是com后缀的,国内依旧没法用。

我们来看下这个js内部有哪些东西,打开这个链接查看js文件:https://maps.google.cn/maps/api/js

可以看到,里面定义了很多资源链接,有些是com的,有些是cn的,而cn在国内是可以访问的,com的就不行。

到这里,就已经发现问题了!

现在就要分析问题,如何让这个js文件在国内通畅使用呢,这个时候我第一想到的词就是”Nginx反代”,如果我们自己有一台国外服务器,使用nginx去反代js里的这些资源链接,不就解决问题了吗。

可是,看上去里面有很多链接,该如何有效的提取出来,然后写成nginx配置文件呢,这里我想到了Python,它一定很擅长干这种事情!

废话好了,下面开始上菜了。

一、安装Python URLExtract库,可以获取文本中的链接地址,地址:https://github.com/lipoja/URLExtract

pip install idna
pip install uritools
pip install urlextract

二、安装Python Requests库,地址:https://github.com/requests/requests/

pipenv install requests

三、python自动生成nginx配置文件代码,代码中用到了2个我自己的域名:api.googlemaps.world和mapsapis.googlemaps.world,如果你自己部署,也需要有一个主域名(不要求是api二级域名)和一个二级域名mapsapis(必须是mapsapis,否则google会返回403)

# -*- coding: utf-8 -*-
import hashlib
import requests
from urlextract import URLExtract

sourceurl = "https://maps.google.cn/maps/api/js"
maindomain = "api.googlemaps.world"
mainapidomain = "mapsapis.googlemaps.world"

def getmd5(txt):
    hl = hashlib.md5()
    hl.update(txt.encode(encoding='utf-8'))
    return hl.hexdigest()

def getAllLink(txt):
    extractor = URLExtract()
    urls = extractor.find_urls(txt)
    return urls

def save(filename,content):
    with open(filename,"w") as w:
        for row in content:
            w.write(row+"\n")
            
def main():
    source = requests.get(sourceurl)
    alllink = getAllLink(source.text)
    linkdata = []
    
    for link in alllink:
        if "https" in link and link not in linkdata and "www.google.cn" not in link and "maps.google.cn" not in link:
            linkdata.append(link)

    replacefilter = []
    location =[]
    alldomain = []
    for row in linkdata:
        if(len(row)>0):
            domain = row.replace("https://","").split("/")[0]
            if domain in alldomain:
                    continue
            alldomain.append(domain)
            
            if "maps.googleapis.com" in row:
                replacefilter.append("replace_filter %s %s ig;"%(domain,mainapidomain))
            elif "www.google.com" in row:
                replacefilter.append("replace_filter %s %s ig;"%(domain,"www.google.cn"))
            else:
                md5val = getmd5(domain.replace(".",""))
                replacefilter.append("replace_filter %s %s ig;"%(domain,maindomain+"/"+md5val))
                location.append("location /%s/ { proxy_pass %s; }"%(md5val,"https://"+domain+"/"));                
    
    #save nginx config
    save("replace.conf",replacefilter)
    save("location.conf",location)
    
if __name__ == "__main__":
    main()

运行后,会生成replace.conf、location两个文件,可以直接在nginx配置文件中include。

replace.conf文件内容:

replace_filter mts0.google.com  api.googlemaps.world/e173754b3b1bbd62a0be9c4afea73fdf ig;
replace_filter mts1.google.com  api.googlemaps.world/ce60bcadc66cea58583ddd700f7d80be ig;
replace_filter khms0.google.com api.googlemaps.world/e6ff3de47e3134794d4442b83c841f20 ig;
replace_filter khms1.google.com api.googlemaps.world/da42f38f94ce6ac80e2806122a7b1933 ig;
replace_filter www.google.cn api.googlemaps.world/2b12936687f366829934645e4ed39807 ig;
replace_filter khms0.googleapis.com api.googlemaps.world/7abac8c11716f6949e7b23f76e60fcd0 ig;
replace_filter khms1.googleapis.com api.googlemaps.world/444c94a4157de3c06c435132eb2f1ac5 ig;
replace_filter mts0.googleapis.com api.googlemaps.world/c7d52b85d86a06df50621e669557ea05 ig;
replace_filter mts1.googleapis.com api.googlemaps.world/57cf283b871304a296c3bd8acde4cc22 ig;
replace_filter maps.gstatic.com api.googlemaps.world/3e0ae61058d4e7be83d222fb1f107310 ig;
replace_filter csi.gstatic.com api.googlemaps.world/ae5102db1431e3fd01dc8336085d150f ig;
replace_filter maps.googleapis.com mapsapis.googlemaps.world ig;
replace_filter maps.google.com api.googlemaps.world/946eb25413c43b235b5806e999044125 ig;
replace_filter gg.google.com api.googlemaps.world/dcd331573c0980eab6fe7346468e9974 ig;
replace_filter www.google.com api.googlemaps.world/468724d08bce9811e989b526c6222863 ig;
replace_filter ditu.google.cn api.googlemaps.world/8867db20717c9aec847667cc7056d755 ig;
replace_filter khms.google.cn api.googlemaps.world/0a68229ef53c18f5fc37f4106f09a6c9 ig;
replace_filter earthbuilder.googleapis.com api.googlemaps.world/e55bb777699a599b09d3011043439a06 ig;
replace_filter mts.googleapis.com api.googlemaps.world/471b015572d3907c09789af41061e964 ig;
replace_filter static.panoramio.com.storage.googleapis.com api.googlemaps.world/3a4544842f4e8e90a152257489cb594d ig;
replace_filter lh3.ggpht.com api.googlemaps.world/85471b91952baa51514c7fad7c57b8eb ig;
replace_filter lh4.ggpht.com api.googlemaps.world/44b3a55364b2f63e51f2c6e911f8506f ig;
replace_filter lh5.ggpht.com api.googlemaps.world/3cc4fbda8f98767ab275af32669f56d4 ig;
replace_filter lh6.ggpht.com api.googlemaps.world/2815063fda2dd0ccf9c566d1f089d4bc ig;

location.conf文件内容:

location /e173754b3b1bbd62a0be9c4afea73fdf/ { proxy_pass https://mts0.google.com/; }
location /ce60bcadc66cea58583ddd700f7d80be/ { proxy_pass https://mts1.google.com/; }
location /e6ff3de47e3134794d4442b83c841f20/ { proxy_pass https://khms0.google.com/; }
location /da42f38f94ce6ac80e2806122a7b1933/ { proxy_pass https://khms1.google.com/; }
location /2b12936687f366829934645e4ed39807/ { proxy_pass https://www.google.cn/; }
location /7abac8c11716f6949e7b23f76e60fcd0/ { proxy_pass https://khms0.googleapis.com/; }
location /444c94a4157de3c06c435132eb2f1ac5/ { proxy_pass https://khms1.googleapis.com/; }
location /c7d52b85d86a06df50621e669557ea05/ { proxy_pass https://mts0.googleapis.com/; }
location /57cf283b871304a296c3bd8acde4cc22/ { proxy_pass https://mts1.googleapis.com/; }
location /3e0ae61058d4e7be83d222fb1f107310/ { proxy_pass https://maps.gstatic.com/; }
location /ae5102db1431e3fd01dc8336085d150f/ { proxy_pass https://csi.gstatic.com/; }
location /946eb25413c43b235b5806e999044125/ { proxy_pass https://maps.google.com/; }
location /dcd331573c0980eab6fe7346468e9974/ { proxy_pass https://gg.google.com/; }
location /468724d08bce9811e989b526c6222863/ { proxy_pass https://www.google.com/; }
location /8867db20717c9aec847667cc7056d755/ { proxy_pass https://ditu.google.cn/; }
location /0a68229ef53c18f5fc37f4106f09a6c9/ { proxy_pass https://khms.google.cn/; }
location /e55bb777699a599b09d3011043439a06/ { proxy_pass https://earthbuilder.googleapis.com/; }
location /471b015572d3907c09789af41061e964/ { proxy_pass https://mts.googleapis.com/; }
location /3a4544842f4e8e90a152257489cb594d/ { proxy_pass https://static.panoramio.com.storage.googleapis.com/; }
location /85471b91952baa51514c7fad7c57b8eb/ { proxy_pass https://lh3.ggpht.com/; }
location /44b3a55364b2f63e51f2c6e911f8506f/ { proxy_pass https://lh4.ggpht.com/; }
location /3cc4fbda8f98767ab275af32669f56d4/ { proxy_pass https://lh5.ggpht.com/; }
location /2815063fda2dd0ccf9c566d1f089d4bc/ { proxy_pass https://lh6.ggpht.com/; }

这里说明下,replace文件中使用的命令replace_filter是nginx的第三方库(https://github.com/openresty/replace-filter-nginx-module),可以方便的替换http响应内容中的字符串,把资源链接替换成我们自己的链接,而location文件中,则对应了location规则,把我们自己的链接在再反代到官方的原始链接上去。

最终,nginx的配置应该是这样纸的:

location /maps/ {
    #这里定义可以使用此接口的ref来源,不需要的可以注释
    valid_referers none blocked nicebing.com *.nicebing.com;
    if ($invalid_referer) {
        return 403;
    }

    #MIME TYPE
    default_type text/javascript;
    
    #删除编码
    proxy_set_header Accept-Encoding '';
    
    #代理地址
    proxy_pass https://maps.google.cn/maps/;
    
    #替换参数
    replace_filter_max_buffered_size 500k;
    replace_filter_last_modified keep;
    replace_filter_types  text/javascript application/javascript;
    
    #载入详细的替换规则
    include vhost/googlemap/replace_cn.conf;
}

location /maps-api-v3/ {
    proxy_pass  https://maps.google.cn/maps-api-v3/;
}

#载入更多详细的location规则
include vhost/googlemap/location_cn.conf;

最后,您可以免费使用我本人自己部署的反代服务,希望能对各位开发项目时遇到谷歌地图需求时有帮助。

<script src="https://api.googlemaps.world/maps/api/js?key=YOUR_GOOGLEMAP_API&callback=initMap&sensor=false" async defer></script>

(备注:请低调使用,低调传播)

查看使用案例:

Nicebing:https://www.nicebing.com

卫星图像加载ok:

地图模式加载ok: