Monthly Archives: 十月 2017

VueJS项目调试(debug)

 

Vue.js devtools开发工具

Vue.js devtools开发工具

上图蛮有意思。

VueJS用了很久了,大部分时候看下报错信息,结合Vue.js devtools查看下各个组件的数据其实就可以了,但是有时候还是有必要使用debugger的。

话分两头,本文主要讲两个东西:

  1. Vue.js devtools开发工具的使用;
  2. 使用debugger和sourcemap调试Vue组件(重点)

一、Vue.js devtools开发工具的使用

在Chrome或Firefox浏览器的扩展插件仓库里搜vue devtool,安装Vue.js devtools后结合下面这张官方动图,其他就不多说了,这不是本文重点。

二、使用debugger和sourcemap调试Vue组件

针对vue-cli webpack官方脚手架,打开build/webpack.dev.conf.js文件,找到下面这句:

将其修改为:

要修改的地方已经都改好了,就是这么简单,惊不惊喜,意不意外。

现在是具体调试了。假设我们想调试App.vue这个组件,可以在想要调试的代码前添加debugger方法,如下图所示:

然后运行npm run dev(如果你没改命令的话,默认开始命令是这个),启动服务后刷新页面(刷新前先把浏览器开发者工具打开),可以看到在程序进入App.vue组件mounted这个组件生命周期钩子里后,指定到debugger处时程序就被debug了。如下图所示,剩下的大家应该都很熟悉了。可以看到,此处显示的代码就是我们组件里的实际代码,并非被我们编译混淆后的那种代码,可读性非常好。

Charles,web请求代理工具

作为一名web程序员,不论你是前端、后端还是全栈,你肯定都会碰到http请求。如果我们只是在PC端常规的网页浏览器上发起http请求的话,通过浏览器开发者工具自带的network相关工具可以很方便的查看请求头、请求参数、请求方法、响应头、相应内容等数据。但是如果我们开发的页面是放在移动端比如微信里面使用的,有时候我们会需要可以直接在电脑上查看手机上发出的http请求和响应数据,或者至少这在很多情况下会让事情变得简单。Windows系统里我们可以用Fiddler,对于我们Mac系统用户而言,Charles这个软件可以帮你解决这个需求。使用方法如下:

一、获取PC端本机内网IP地址

在终端输入ifconfig来查看本地的内网ip地址:

如上所示,本机内网ip地址为192.168.0.102。

二、配置手机代理

配置前请先确保手机和PC连接的是同一个wifi网络,即它们处于同一个局域网内。手头现在用的是iPhone 5s,故此处以该机截图为例进行展示。

设置=》无线局域网,得到下图:

选择PC端所连的wifi网络,然后点击右侧的蓝色感叹号,在新界面拉到底部,得到下图:

按上图进行配置(一共配置2个地方):

  1. 服务器地址处填写我们之前获取到的PC端内网ip地址;
  2. 端口处填写“8888”(固定值)。

然后点击左上角【<无线局域网】返回键返回上一界面的同时会保存好我们配置的信息。

三、开始使用Charles监听数据

如果按上述操作进行操作后,你发现手机网络好像有点问题,出现这种情况是因为你没有打开PC端的Charles客户端。打开PC端的Charles软件,然后手机上随便访问几个页面,就会看到有很多请求数据了。具体数据的查看方法跟常规PC端浏览器开发者工具里的用法大同小异,不复赘述。下面放一张有数据的截图。

四、注意事项

关闭Charles后需要去掉我们刚才在手机上设置的代理ip和端口,否则手机访问网络会有问题。

微信跨公众号支付功能开发总结

本周团队里我分到的开发任务之一微信公众号的支付功能,需要和北京的一个java同事合作完成。搞了两天终于搞定。怕忘记具体流程,这里简要记录一下:

本文所指的微信跨号支付指的是如下的场景:

用户小明在微信公众号A里成功走完流程提交了一笔订单后点击页面上的支付按钮,吊起微信支付弹框,确认金额后输入密码即可完成支付。不过通常情况下这笔钱是支付给当前微信账号的,我们现在的场景是公众号A所属公司的营业性质不具有这个支付业务的收款权限,同公司另一个子公司(公众号B所属公司)具备相应牌照可以进行该类性质款额的收取,所以用户吊起微信支付弹框后我们需要让实际的收款公众号为微信公众号B。

首先我们要知道微信测试号是没有微信支付权限的,所以我们必须用微信正式号来测这个功能。在开始开发微信支付功能之前,微信正式号上需要先申请微信支付功能,这个是开发的前提,因为给我的正式号已经申请了这个功能,所以具体的流程并不清楚,反正是掏钱的活。

下面我们分别对两个微信号进行配置,每个微信号会分别用到一个域名。这两个域名不能是IP地址,也不能是http/https默认端口号之外的各种端口号。

测试号(微信号A,发起付款操作的微信号)配置:

我们微信测试号的前端文件之前一直是直接用ip地址访问的,我相信类似情况的朋友应该也不少,但是用ip的话我们是没办法测微信支付功能的,以前负责这块的后端同事是在生产环境试的(那时候生产环境还未上线),所以没涉及到这个问题。我们测试环境用的是apache,搜了下网络上的文章,配置了下代理,绑定了一个生产环境用的已经备案了的主域名的二级域名到这个测试服务器上(apache设定代理的文章网络上已经很多了就不写了,这里只提醒一下没有域名绑定经验的人:绑定域名出了在服务器端做好代理配置,还需要登录域名管理系统上指定域名要绑定的ip,这样访问域名时才会访问到我们的服务器,然后服务器根据我们的配置和请求来源的域名来判断转发请求到哪个服务上)。

测试号上主要的信息和配置点如下:

1、测试号信息、接口配置信息、JS接口安全域名:

appId前端和后端都可能会用到,谁要弄微信跳转地址就必须用到这个值。appID和appsecret都是腾讯给你配好的固定的值,无法修改。

【接口配置信息】里的URL和Token是需要我们自己填写的信息。这个是微信和我们自己的服务器互相校验用的。简单说明一下,这里当我们填完URL和Token的值后点击确定想保存时,微信会发起一个GET请求到我们填写的URL地址上,我们需要在该URL的GET请求(POST请求另有他用,所以这个接口地址请务必对GET和POST请求区别对待)中校验微信发来的请求里的签名,校验通过才可以相信当前这个请求是微信官方发过来的,然后将微信请求传过来的echostr重新返回给微信服务器,至此双方服务器算是互相认可了-_-,只有在微信服务器成功接收到你在接口中返回的echostr后,你在【接口配置信息】里填写的Token值才会被保存起来,否则微信会在页面上提示保存失败的。

JS接口安全域名是用来指定允许调用微信JSSDK的域名,也就是我们前端页面所在域名(不需要包含url中的路径和http://或https://这种协议部分的内容)。在测试号中,此处可以是subdomain.domain.com这样的域名,也可以填写111.222.33.44这样的ip地址。微信JSSDK是什么东西?如果你做过iOS/android内嵌react-native/html页面的项目的话,你应该会碰到需要原生应用暴露一些方法给你调用的场景。微信JSSDK其实是差不多的东西,他提供了浏览器默认API之外的一些API,有些API比如本文提到的微信支付是浏览器默认API中不存在的新功能,有些API比如拍照的用户体验会比input[type=file]调起来的原生拍照的用户体验好很多。这里因为我们后面要用这个测试号进行微信支付,而发起微信支付需要使用域名(如果只是用用拍照这些API,用ip是没问题的),所以此处需要填写域名而非ip地址。

2、授权用户获取基本信息/网页授权回调域名

点击下图中【网页账号】=>【网页授权获取用户基本信息】右侧的【修改】按钮。

然后会出现这样的弹框,因为通常我们调用微信JSSDK是所在的域名跟我们获取用户信息所要跳转到域名是一致的,所以此处就按我们上面填写的JS接口安全域名来填写就行了,也是不需要包含url路径和http://或https://这种协议部分的。我们显然知道这个地址的用途,但是这个地址是如何使用的呢?微信网页授权获取用户信息有两种方式,一种是需要用户点击同意进行授权,一种是不需要用户手动点击同意的,两种授权方式都能获取到用户的部分信息,区别主要是前者能获取到的信息相对多一些,但是后者的优点是不扰民,我实际项目中用的都是后面这种“静默”方式来获取用户信息。微信网页授权获取用户信息需要使用下面这种微信跳转地址:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

这个地址中大写的APPID、REDIRECT_URI、SCOPE和STATE部分都只是占位符,需要根据实际情况进行替换。微信官方有关于微信网页授权的介绍,具体可以到这个地址去查看:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

稍微备注下REDIRECT_URI,这个地方要填写的是编码后的地址,并且是允许带查询参数的。这个编码的操作,在浏览器端就是encodeURIComponent(‘http://www.baidu.com/test/index.html?q=example’)后得到的”http%3A%2F%2Fwww.baidu.com%2Ftest%2Findex.html%3Fq%3Dexample”这样的字符串。用户再点击微信跳转地址(一般直接绑定到微信菜单上)后,就会跳转到被我们编码的那个地址(http://www.baidu.com/test/index.html?q=example)上,并且还在会这个地址后面追加一个code查询参数。该参数每次都是随机生成的,并且每个code都只能被使用一次(如果不使用,code的有效期最长可以保留5分钟,超过这个时间也会过期作废),其作用是服务端可以根据code来查询用户的openid,openid是用户在某个公众号里的唯一id,并且用户取消关注该该公众号然后重新关注该公众号后,新的openid跟之前的openid也是一样的值——其实这个openid只跟公众号和用户微信号有关系,只要这两个变量不变,openid就不会变。还要提醒的是,获取用户openid只是需要跳转地址跳一下拿到用户code后就能拿到用户openid的,并不需要用户去关注公众号,本文提到的跨微信号支付功能也利用了这一点。

微信号B(授权的微信号)配置:

在这里也需要配置微信网页授权回调域名(假设此处我们配置的域名是pay.example.com),配置方式跟上面说的差不多,唯一的区别是页面上会给你一个当作证明文件的txt文本文件,你需要把他上传到你的服务器上,并且要可以访问,否则配置完后是无法保存的,还有就是这个保存操作一个月只有3次机会(保存失败不会计数的,保存成功了才算作一次)。

URL和Token这个地方,如果仅仅是问了完成本文提到的微信跨号支付功能的话,是不需要填写的,反正我们这次没填写,不影响微信支付。

然后是配置微信支付授权目录,如下图所示,最多可以添加5个。

这里填写的支付授权目录是你在微信号A里发起支付请求是页面所在url的完整路径,长得类似下面这种样子:

http://subdomain.domain.com/a/b/c/d/

几个需要注意的地方:

  • 路径必须以“/”结尾;
  • 这里只填写到路径部分,不填写资源文件名、查询参数等内容。比如如果url是http://subdomain.domain.com/a/b/c/d/index.html?q=example的话,我们要填写的授权目录指的是index.html前面的这一部分;
  • 网络上有文章指出这里的目录层级需要时二级或者三级,但是正如上面示例所示,我用四级并没有问题。具体应该用几级不是随意的,还是拿http://subdomain.domain.com/a/b/c/d/index.html?q=example这个url为例,这里如果你授权目录没填写到d这里而是填写到了a或b或c就无法进行支付操作了——对了,授权目录需要填写到页面url中最深的路径部分。如果url是http://subdomain.domain.com/a/b/c/test.html,我们的授权目录就需要填写http://subdomain.domain.com/a/b/c/;
  • 强调下,此处的授权目录是根据发起请求时页面所在url来填写的,跟我们在微信号B中配置的pay.example.com这个域名之间没有任何关系,两者甚至都不需要是同一个根域名。正如上面示例的一样,我们这里填写的授权目录里的域名部分是跟微信号A里的相一致的,而非微信号B。

总操作流程:

用户在支付页面点击我们页面里的支付按钮,然后前端使用微信跳转地址跳转到微信pay.example.com开头的一个后端提供的接口上去,这个时候相当于对这个后端接口发起了一个get请求,服务端根据微信在接口后面追加的code查询参数来获取微信号A的用户在微信号B中对应的openid(用户无需关注微信号B),然后服务端在响应前端get请求时进行重定向返回到用户先前访问的支付页面并在新的url后面追加openid参数参数(微信号A的用户在微信号B中的openid),然后前端页面检测url中是否带有openid来判断是否需要通过js自动触发请求到服务端查询一些微信统一支付的参数来在客户端调启微信支付控件。大概就是这么个意思,实际操作中我们会对接口追加一些诸如告诉服务端重定向要定向到的地址,支付页面所在订单的id之类的参数。下面这种吊起维系支付控件的方式是不需要经过微信JSSDK授权的,两个不是一回事,因为用的不是微信JSSDK里的支付API。

非微信JSSDK方式调启微信支付控件的代码示例:

 

MAC Pro下使用IntelliJ IDEA创建maven spring mvc项目

为了接下来能比较容易上手后端项目,结合目前所做项目的后端开发们使用的是spring mvc而非spring boot。决定先把基本的java开发环境配置好,先跑一个本地服务能看到页面再说。我是按着http://www.cnblogs.com/Sinte-Beuve/p/5730553.html这篇文章的教程来的,所以内容大体一致,再写一遍主要是为了加深自己的印象。

最最基础的,你需要先装好java、maven和tomcat(tomcat选装,如果用jetty等其他web容器,就用不到tomcat了,不过tomcat还是用的最广泛的,出于学习的目的,还是装下比较好),这部分内容之前有写过文章《Macbook Pro安装Maven 3 》。然后开始下面的流程:

一、预备信息

因为软件什么的更新频率还是蛮快的,我先亮一下我用的软件相关信息,咱们的工具越像的话,这篇文章的参考价值会越高:

关于IDEA:

其他信息:

二、用maven创建webapp骨架

首先,菜单栏:File=>New=>Project…,然后按下面这样操作:

  1. 选择Maven;
  2. 勾选Create from archetype;
  3. 选择org.apache.maven.archetypes:maven-archetype-webapp;
  4. 点Next。

然后填写GroupId、ArtifactId,版本号默认1.0-SNAPSHOT就行:

再一个然后,选择maven相关设置(/Users/yakima/.m2/settings.xml这个文件我本地还没有,截图里这个是默认的路径,我用maven中央仓库速度就挺好的了,这种demo项目也不涉及私有架包,所以感觉目前也没必要写一个setting.xml文件,都用默认的就好了),这里选一下Maven home directory里的东西就可以了。

然后填写项目名和项目地址,最后点击Finish按钮:

三、完善项目目录结构

下面是最终的目录结构(如果按上面的步骤走到这里,你的目录结构肯定跟这里是有差异的,先放出来是为了让大家有个大概的轮廓在脑子里,而且下面单独说文件的时候也不至于出现不知道我说的文件该放在哪个位置的问题)。

src/main/java:开发目录(程序源码,Sources Root)

src/main/java目录本来是没有的,是我们手动添加的目录,请注意java目录的图标是有特别的颜色的(截图里是蓝色),这是我将其标记为Sources Root目录的结果,只有将文件夹标记为Sources Root后,才能通过IDEA右键该文件夹后通过菜单直接在其下创建package和class。要将一个目录标记为Sources Root,只需要鼠标右键该文件夹=>Mark Directory as=>Sources Root。将src/main/java目录标记为Sources Root后在其下创建com.example.controller包,并在controller同级位置创建dao、pojo和service三个微笑(就叫微笑吧,我不知道这个该叫啥,下面一个文件都没有,不知道算不算包-_-)。

src/main/resources:资源目录(Resources Root)

资源目录下的文件是会被编译到输出目录下的。跟上面标记src/main/java目录的方法类似,若src/main/resources目录尚未被标记为Resources Root则需要手动将其标记为Resources Root。不过好像这个文件夹默认就已经被标注为Resources Root了。

src/test:单元测试目录

下面的开发目录为src/test/java,资源目录为src/test/resources。

四、配置Maven的pom.xml

完整的配置文件贴于此:

更新完pom.xml后,IDEA应该会自动下载相应的jar包,如果没有自动下载,请手动右键pom.xml文件,选择Maven=>Reimport来手下载相应的jar包。

五、配置web.xml

maven项目默认生成的2.3版。覆盖为以下内容:

其中DispatcherServlet是分发http请求用的。

六、配置contextConfigLocation

在刚才的web.xml文件中,可以看到contextConfigLocation这个param name,其值为classpath:spring/spring-mvc.xml。我们在src/main/resources下新建一个spring目录,并在其下新建一个spring-mvc.xml文件。spring-mvc.xml文件的内容如下:

七、配置log4j.properties

日志文件是debug中一个不可缺少的工具,因此添加log4j日志包。在src/main/resources下新建log4j.properties文件,该配置文件内容如下:

八、controller和view的编写

在src/main/java/com.example.controller下新建HomeController文件,内容如下:

在src/main/webapp/WEB-INF/views下新建index.jsp文件,内容如下:

至此,基本的代码编写工作就完成了。

九、servlet容器的配置和运行

servlet容器有两种配置方式:

  1. 配置本地的tomcat服务器;
  2. 配置maven插件;

下面分别介绍(要跑服务的话,只要配一个就可以了,当然你配两个选一个来跑也是可以的)。

方法一:配置本地的tomcat服务器

菜单栏=>Run=>Edit Configurations…,然后按下图操作:

请注意,上图3处的Update classes and resources选项一开始是没有的,一开始只有一个Restart Server选项。需要点击Server选项卡旁边的Deployment选项卡,点击+号=>Artifact…来添加war exploded,然后再切换回Server选项卡,这时候就有Update classes and resources这个选项可以选来。

方法二:配置maven插件

maven插件有tomcat和jetty等,两者都是servlet容器。jetty插件的配置我们已经在pom.xml文件中完成了。现在在IDEA中配置jetty。

菜单栏=>Run=>Edit Configurations…,然后按下图操作:

十、运行程序

选择jetty或tomcat然后点击Run按钮即可,示例如图(选择了tomcat):

Macbook Pro安装Maven 3

可能是xcode还是什么鬼,反正我本子里已经装好了java:

不过JAVA_HOME环境变量尚未设置,需要设置。在这之前,我从maven官方网站下载了一个apache-maven-3.5.0-bin.zip压缩包并将其解压到了/usr/local/apache-maven-3.5.0目录上。

准备工作做好后,打开~/.bash_profile文件(若没有则新建之):

保存并退出文件(esc两次后输入:wq!并回车)。执行下面的命令,mvn命令马上就可以用了,

然后我发现一个坑,就是每次我重启终端或者重启电脑后mvn变量又不能用了,这显然是不行的。我用的是zsh,参考网上的资料,打开~/.zshrc文件并在末尾添加上面那句话并重启终端后mvn命令就可以用了(每次启动终端前,会自动运行一次~/.zshrc里的命令,不需要手动去source了)。

修改完以上内容后可以查看对应的变量名的值来确认下:

这时候maven已经装好了:

 

微信端上传图片前先压缩图片

我们的场景是前端SPA应用有两个入口,一个是我们自己的微信公众号(可以实现微信授权,调用微信JSSDK),一个是第三方的公众号(需要第三方支持才能实现微信授权),出于统一和方便的考虑,上传照片功能没有使用微信JSSDK里的选择图片和上传图片相关方法,而是用传统页面里上传图片的方式。上传图片常见的有两种方式,一种是上传图片base64数据,一种是上传文件blob对象。这里我们选择的是上传文件blob对象。现在的问题是,服务端尤其是大部分tomcat里配置的post请求允许接收的最大数据量好像是2M,现在手机的像素都很高里,很容易就会拍出来大于2M的照片的,而且就算没有服务端限制,上传2M甚至更大的图片的速度会比较慢,对用户的体验也不好。所以今天趁着有空,自己做了个图片压缩的功能上去。直接上代码吧,下面是封装的压缩图片文件(blob对象)的方法,外部调用这里的compressImage方法(该方法返回的是一个Promise对象):

调用该方法的示例代码如下,注意这里compressImage方法前面有个await,因为这个方法是异步的,需要用await去等待它返回结果(resolve或reject)。另外需要注意的是data.append是可以接收第三个参数表示文件名的,我不加这个参数的时候接口会报错,看了响应头并上网看了些资料,发现问题应该是由于通过canvas进行图片压缩导致文件名等信息丢失导致发请求时body里少了文件名,写这个接口的后端貌似会通过文件名后缀进行一些判断,所以我如果请求体里少了filename或者filename的值不带有图片名后缀,接口就会报错,需要通过给append方法传入第三个参数来特别指定带有图片名后缀的文件名。

相关的html部分代码如下,这里需要说明的是,如果input标签不加上accept=”image/*”属性的话,会出现在安卓手机微信客户端里只能选择用户手机本地图片不能进行拍照的问题,在iOS系统微信客户端里没有这个问题:

Github上有我调研时参考别人的代码写的类似的代码实现demo,具体可以访问https://github.com/Yakima-Teng/iframe-application/tree/master/pages/upload查看。