使用Squid实现appstore应用离线分发下载(支持ios9)

来源:互联网 发布:知乎akb研究生 编辑:程序博客网 时间:2024/05/16 07:31

1 前言

        我们公司自己开发和运营移动app,平时会有地推人员在户外进行app下载的推广.因为下载要消耗流量,很多用户并不愿意用自己的数据流量下载,这就需要下载的地方能提供无线wifi.但因为推广的地方都是临时租借,一般没有稳定的网络,只能通过3G路由器来提供给用户下载.这样依然很难得到理想的速度,并且流量费也是很大一笔费用.

        这时候我们就在考虑能不能通过把下载的文件放到局域网内,通过搭建局域网服务器的方式来提供给用户下载.对于android应用来说这是毫无问题的.携带一台笔记本甚至在手机上通过软件搭建一个http服务都可以实现文件的分发.但是对于ios来说,因为应用都要通过appstore来下载.所以直接搭建http服务的方式显然不可行.经过试验发现,通过搭建一个透明代理服务器,再在代理服务器上进行缓存,可以实现直接直接从局域网下载苹果app.最终效果是下载速度大幅度提高,并且节约了大量的流量费用.

2 通过iptables + squid实现透明代理

        首先介绍一下所使用的系统和软件版本:

        操作系统:centos 6.6 64bit

        squid: 2.7 版本(重要,一定要使用2.7版本,后面会介绍原因)

        经过搜索我们发现我们的需求和squid实现透明代理有点像,只不过这东西通常用在CDN服务器或者大型的局域网(例如长城宽带)用来进行加速这类场景.所以我们先搭建了一个机遇iptables和squid的一个基本的透明代理环境,实现iptables的nat转发请求到squid端口,处理后访问外网.这不是本帖的重点,请参考以下链接,有问题可留言交流.

        squid安装:http://hx100.blog.51cto.com/44326/339137/

        iptables+squid配置:http://blog.chinaunix.net/uid-23152265-id-2535823.html

        我的外网网口为ech0:192.168.1.2,内网为eth1:192.168.10.1.

3 在squid中实现对apk和ipa的缓存.

        有了上述基础环境之后,下面我们针对我们自己的需求来详细说一下跟缓存相关的几个配置.

cache_mem 500 MB #内存缓存大小memory_replacement_policy lru #更新方式,lru即可maximum_object_size_in_memory 50 MB #缓存到内存中的最大对象大小,跟你的app差不多机型.50M启动的时候会有警告,无视掉.cache_dir ufs /usr/local/squid/spool 20480 16 256 #磁盘缓存文件大小及目录结构,当前配置的含义是磁盘缓存大小20G,一级目录16个二级目录256maximum_object_size 100 MB # 磁盘缓存最大文件大小,稍大于内存缓存文件即可.cache_swap_low 80 # 忘了,懒得copycache_swap_high 95 # 忘了,懒得copyacl CACHE_OBJ urlpath_regex .png .jpeg .jpg .js .apk .ipa # 定义一个acl表示要缓存的文件,关于acl的定义可以参考官方文档.cache allow CACHE_OBJcache deny all

        以上是我使用的内容. 修改了缓存配置之后别忘了删除掉缓存目录并重建缓存,重启squid.

        如果一切正常的话,那么squid已经可以正常缓存ipa/apk文件了,你可以找一个apk文件试验一下比如:http://dldir1.qq.com/weixin/android/weixin637android660.apk,下载的同时查看squid的access.log日志,你会发现第一次下载时为TCP_MISS,第二次下载已经变成了TCP_MEM_HIT,证明已经命中了内存缓存.从下载速度方面应该也能有一个数量级的提高.

4 使用storeurl_rewrite_program缓存动态参数url.

        大部分情况下以上三步骤已经可以缓存apk/ipa文件了,但是在ios9之后,新上传的应用链接和以前发生了变化.以前的文件直接是apk结尾,现在的文件链接形如:http://iosapps.itunes.apple.com/apple-assets-us-std-000001/Purple69/v4/26/63/28/266328a6-6893-3d23-e58e-4b54bea24a30/pre-thinned3169899445757707662.thinned.signed.dpkg.ipa?accessKey=1447486548_7206112169011419132_PdeyZRmeDfRHz5lpkhqrYFbOCzalZKWAv9uo8uM1F2OpGnbuluHjJci40yZJGReraNg3uNI0fzgvNvK4xSW7ToQzJZKBhXaX5cNstgEKBbUE1tbHHCx6d%2Fvig0ZArOoTditDPP%2BUt0Bt7YTsle6roEcumREx3%2FGpjUCwqwh50AvrO402PD3Z0uLM9XA2QHFUgfl0WpNxWsK7K9g6R483nBMdowFBWlI3o3VASs3AWLU%3D ,带了一个accessKey的动态参数.这样在默认情况下,每次访问的url都不同,是没办法缓存到一个结果上的.所以针对这个情况,查了一些资料,发现使用storeurl_rewrite_program的方式可以解决这个问题.

        storeurl_rewrite_program是squid2.7提供的一个自定义模块.默认不启动.所需要的参数是一个可执行程序.当配置了这个程序,squid会把访问的url作为参数传给程序,程序处理完了之后回传的参数作为storeurl寻找缓存.例如当前访问的连接为http://a.com/abc.apk?token=123和http://a.com/abc.apk?token=456,默认情况下这会被当做两个连接无法命中同一个缓存.使用storeurl_rewrite_program之后,我们可以通过程序将这两个连接同时映射到http://a.com/abc.apk,这样访问了第一个url之后,第二个url的访问将会命中第一个url的缓存.关于storeurl_rewrite_program的使用方法可以参考:http://www.squid-cache.org/Doc/config/storeurl_rewrite_program/.这里我贴上我的program和配置:

配置文件:

acl CACHE_IPA urlpath_regex .ipa #针对ipa进行处理storeurl_rewrite_program /usr/local/squid/store.py #处理程序的路径storeurl_access allow CACHE_IPAstoreurl_access deny all

store.py:

#!/usr/bin/env pythonimport syswhile True:        read = raw_input()        url = read.split()[0]        start = url.find('iosapps.itunes.apple.com')        end = url.find('.ipa')        ipaurl = url[start:end]        result = "http://" + ipaurl + ".ipa\n"        sys.stdout.write(result)        sys.stdout.flush()


注1:这里我只处理了新的带有动态参数的appstore里ipa的下载情况,老的不带参数的下载情况大家自行处理.

注2:storeurl_rewrite_program只有squid2.7提供了,其他版本都没有.squid3.4之后提供的storeid_rewrite_program提供了类似的功能,有兴趣的可以尝试一下.

注3:传入参数通过raw_input()接收,传出参数不能直接print,而应使用sys.stdout.flush()来输出到stdout,避免使用buffer,其他语言也类似.务必小心.

按上面的程序,原链接会被处理为 http://iosapps.itunes.apple.com/apple-assets-us-std-000001/Purple69/v4/26/63/28/266328a6-6893-3d23-e58e-4b54bea24a30/pre-thinned3169899445757707662.thinned.signed.dpkg.ipa,经测试下载可以缓存.





0 0
原创粉丝点击