分类
原创作品 技术

亚马逊联盟API上手指南 – Amazon.cn Product Advertising API quick start

该指南旨在帮助使用亚马逊联盟Product Advertising API的开发人员快速上手,开发出一个可以运行的样例程序。该指南的目标读者是对WebService、RESTful Service有一定了解的Java开发人员。

主要步骤:

  1. 注册亚马逊联盟账号;
  2. 注册联盟开发者账号;
  3. 修改并调试样例程序。

注册亚马逊联盟账号

访问亚马逊联盟网站http://associates.amazon.cn,确保选择地区为“中国”,点击“免费加入”按钮,会跳转到登录注册页面,这里可以直接使用你已经注册过的亚马逊(中国)账号,或者新注册一个账号。

下一步进入向导页面,第一步“帐户信息”中选择或新加一个地址,第二步“我的网站模式”照实填(是的,你需要有一个网站,从导购网站到博客都可以),第三步完成即可。提示添加付款信息,输入一张有效银行卡即可,这一步骤以后做也行。

保持登录状态进入联盟管理界面。比如你在第二步中输入的网站ID为“MyWebsite”,那你的默认跟踪ID将为“mywebsite-23”。跟踪ID又叫Associate Tag,用于在用户实际购买过程中识别你的账号,以保证在发生购买时给你分配提成。点击主页左侧“跟踪代码管理”,可以添加额外的跟踪ID,比如“mywebsite-channel1”,点击“搜索”(其实就是创建),会生成“mywebsite-channel1-23”(如果跟已有的重名会生成其他后缀)。

注册联盟开发者账号

登录到联盟管理界面中,点击“Product Advertising API”页签,会跳转到Product Advertising API的介绍页面。基本上这个页面里所有链接都是有用的,但你可以先点击右边的“现在注册按钮”。这里会跳转到美国亚马逊网站的登录注册界面,注意亚马逊美国和亚马逊中国的账号体系是互相独立的,这里可以用你已经注册过的亚马逊美国账号,或新注册一个(可以使用与亚马逊中国相同的邮箱,也可以不同)。进入第二步,账户信息,这次界面是英文的,填英文或直接填中文都可以,记得下面“Check here to indicate……”要打勾,还有输入正确的图片验证码,点击“完成注册”。

在成功界面,点击“管理您的帐户”链接,跳转到管理页面,在“访问标识”栏,点击“点击这里”,你会发现你跳转到了高大上的AWS亚马逊云的管理页面上。如果有“Attention”提示,不用管它,勾选“I understand”,点击“Continue”即可关闭提示。在“Access Credentials”章节的“Access Keys”标签下,你会看到你的“Access Key ID”是一串字母数字(20个字符),点击“Secret Access Key”列对应的“Show”链接,会弹一个提示框,里面会显示另一串字母数字(40个字符),这就是之后会用的Secret Key。因为超过多少时间后就不能在查看Secret Key了,建议把这对Access Key ID和Secret Key记录在一个安全的地方。

 

修改并调试样例程序

回到“管理您的帐户”页面,点击左边的“示例代码”,会来到一个列表页面,里边有各种语言的样例程序,比如node.js、PHP、Ruby、C#、Perl、Java,我们比较关心Java。点击“Product Advertising API Signed Requests Sample Code – Java REST/QUERY”,再点击“Download”下载程序包。Java SOAP的样例也是可以用的,但相比而言REST这个版本更简单些。需要注意的是,经笔者测试,截止到14年3月,在北京联通网络访问AWS系列站点有时会有些慢甚至打不开,挂上香港或国外代理服务器即可恢复正常(API接口调用则不存在这个问题)。

将下载的amazon-product-advt-api-sample-java-query.zip解压,在Eclipse里新建一个普通Java工程,把src目录拷贝进去。然后你会发现工程缺少依赖类库无法编译,去Apache网站http://commons.apache.org/proper/commons-codec/下载一个commons-codec.jar,1.3版本以上即可,放到项目lib目录中,并加入Build Path,编译就应该通过了。

com.amazon.advertising.api.sample.SignedRequestsHelper这个类没有什么要改的,用于生产环境都可以。但com.amazon.advertising.api.sample.ItemLookupSample类里有一些需要调整的地方:

  1. Endpoint(即API所在的服务器URL)修改为亚马逊中国的服务器。别找了,截止到14年3月的版本,注释里都没列中国,但从在线文档(Anatomy of a REST Request)可以找到,CN的Endpoint包括:

    http://webservices.amazon.cn/onca/xml
    https://webservices.amazon.cn/onca/xml

  2. 添加一个Associate Tag常量,并作为参数传到API里去。这个就是你一开始注册的联盟账号里的跟踪ID,没有这个是算不了钱的。
  3. 修改AWS_ACCESS_KEY_ID和AWS_SECRET_KEY为上一章注册的开发者账号中所提供的那对Access Key ID和Secret Key。
  4. 调整API Version参数,样例中的“2009-03-31”版本已经过期,修改为“2011-08-01”。
  5. 样例中的ITEM_ID是美国的商品,改成中国的“B00D2J9ETE”。

执行ItemLookupSample,Run as Java Application。正确的话,会在Console控制台里打出“Signed Title is “Kindle Fire HDX平板电脑””的字样。程序会调用API两次,其实只是为了演示SignedRequestsHelper.sign()方法的两种重载。

如果程序报错,尝试把Console里打出来的“Signed Request is http://webservices.amazon.cn/onca/xml?AWSAccessKeyId=……”那行里的URL复制下来并在浏览器打开,观察返回的XML即可发现问题,比如认证失败、参数无效之类的错误,都会有提示。

为了大家方便,笔者把自己修改版本的SignedRequestsHelper附在文章最后,替换即可。

基于这个样例程序,相信大家已经可以快速上手,下一步可以查看官方Developer Guide文档(在线查看下载离线PDF),开发更多的业务功能,同时也建议大家将API返回XML的解析处理做的更强壮更灵活些。

声明:本文中涉及到的样例程序版权归亚马逊所有,笔者的修改仅为展示API能力,笔者不对其中产生的任何bug负责。

附录

笔者的ItemLookupSample.java源码

public class ItemLookupSample {
    /**
     * Your associate tag, as taken from Associate administration page.
     */
    private static final String ASSOCIATE_TAG = "YOUR_ASSOCIATE_TAG_HERE";
    /**
     * Your AWS Access Key ID, as taken from the AWS Your Account page.
     */
    private static final String AWS_ACCESS_KEY_ID = "YOUR_ACCESS_KEY_ID_HERE";

    /**
     * Your AWS Secret Key corresponding to the above ID, as taken from the AWS
     * Your Account page.
     */
    private static final String AWS_SECRET_KEY = "YOUR_SECRET_KEY_HERE";

    /**
     * Use one of the following end-points, according to the region you are
     * interested in:
     * 
     *      US: ecs.amazonaws.com 
     *      CA: ecs.amazonaws.ca 
     *      UK: ecs.amazonaws.co.uk 
     *      DE: ecs.amazonaws.de 
     *      FR: ecs.amazonaws.fr 
     *      JP: ecs.amazonaws.jp
     *      CN: webservices.amazon.cn
     */
    private static final String ENDPOINT = "webservices.amazon.cn";

    /**
     * The Item ID to lookup. The value below was selected for the US locale.
     * You can choose a different value if this value does not work in the
     * locale of your choice.
     */
    private static final String ITEM_ID = "B00D2J9ETE";

    public static void main(String[] args) {
        // Set up the signed requests helper
        SignedRequestsHelper helper;
        try {
            helper = SignedRequestsHelper.getInstance(ENDPOINT, AWS_ACCESS_KEY_ID, AWS_SECRET_KEY);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        String requestUrl = null;
        String title = null;

        // The helper can sign requests in two forms - map form and string form.

        // Here is an example in map form, where the request parameters are stored in a map.
        System.out.println("Map form example:");
        Map<String, String> params = new HashMap<String, String>();
        params.put("Service", "AWSECommerceService");
        params.put("Version", "2011-08-01");
        params.put("AssociateTag", ASSOCIATE_TAG);
        params.put("Operation", "ItemLookup");
        params.put("ItemId", ITEM_ID);
        params.put("ResponseGroup", "Small");

        requestUrl = helper.sign(params);
        System.out.println("Signed Request is " + requestUrl);

        title = fetchTitle(requestUrl);
        System.out.println("Signed Title is \"" + title + "\"");
        System.out.println();

        //Here is an example with string form, where the requests parameters have already been concatenated
        // into a query string. 
        System.out.println("String form example:");
        String queryString = "Service=AWSECommerceService&Version=2011-08-01&AssociateTag=" 
                + ASSOCIATE_TAG + "&Operation=ItemLookup&ResponseGroup=Small&ItemId="
                + ITEM_ID;
        requestUrl = helper.sign(queryString);
        System.out.println("Request is " + requestUrl);

        title = fetchTitle(requestUrl);
        System.out.println("Title is \"" + title + "\"");
        System.out.println();
    }

    /**
     * Utility function to fetch the response from the service and extract the
     * title from the XML.
     */
    private static String fetchTitle(String requestUrl) {
        String title = null;
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(requestUrl);
            Node titleNode = doc.getElementsByTagName("Title").item(0);
            title = titleNode.getTextContent();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return title;
    }
}

关于IAM

笔者也有在研究亚马逊的AWS,里边有一套IAM服务,非常方便账户权限的管理,比如我可以创建一个账号,只给它S3的权限,其他服务就访问不了,别人冒用了这个用户的认证信息,也不会造成比S3之外更多的影响。如果能使用IAM用户为联盟API提供认证,会更加方便些,但经过一番调研,结论是,截止到14年3月笔者撰文时,IAM不支持联盟API:
http://stackoverflow.com/questions/9689357/is-it-possible-to-generate-an-aws-access-key-via-iam-for-use-with-the-product-ad

分类
English 原创作品 技术 移动互联网

泡面管家Android版开源 – Instant Noodles Master for Android Is Open Souce

专为泡面开发的一键计时器《泡面管家》Android版已开放源代码,并托管于GitHub上。
The One-Tap-Timer for instant noodles, Instant Noodles Master for Android, is now open source on GitHub.

开源项目URL是:
The URL of the open souce project is:

https://github.com/evisong/noodlesmaster

源代码早于2010年已托管在GoogleCode上,于2013年7月迁移至GitHub,原GoogleCode源代码将不再维护。
The souce code is originally hosted on GoogleCode since 2010, and was finally migrated to GitHub on July 2013, since then the copy on GoogleCode will no longer be maintained.

分类
原创作品 视觉主题

原创主题《金光碧色》

笔者偶尔会抱怨BlogEngine.NET的主题太少,很羡慕WordPress丰富的主题资源。前段时间手痒想给博客换个新主题,但找遍WordPress TOP20之类的排行榜也没有发现特别满意的,一想到就算找到满意的也得花功夫改写成BlogEngine.NET的格式,倒不如释放一下自己的原创热情。

evis-me_royalgold-theme_screenshot

素材

首先是页面的CSS布局,从零开始搭CSS是很折腾人的,一个CSS布局模板可以省掉很多辛苦。CSS-Tricks网站提供了一个“完美的自适应宽度的布局”: http://css-tricks.com/the-perfect-fluid-width-layout/,其特点如下。

  • 左右两栏式;
  • 在主流浏览器下效果良好;
  • 宽度最小可以缩减到780px,最大可以增加到1260px;
  • 侧边栏保持固定宽度,并与主内容区域同高;
  • 页面内容在极大分辨率下保持居中。

笔者基于这个布局的源码,将侧边栏移到了右边,微调了最小最大宽度,最主要的,加入了一系列包括边框、阴影之类的背景图片。这个“完美布局”模板在使用时有以下几点需要注意。

  • 侧边栏是float:right属性挤过去的,这意味着主内容区域里不能很早就用clear:right或者clear:both来清理浮动,否则会造成清理之后的内容与之前的内容间产生很大片空白;
  • 主内容要设计min-height,以避免侧边栏内容高度大于主内容时,下半截没有背景的情况;
  • 这个模板包含一些针对IE的CSS-hack,在IE下人工改变浏览器宽度时,渲染效果会有不稳定的情况。

然后是背景。只所以这个主题会有金色系这样的配色,主要还是因为偶然找到了这样的图案纹理: http://speckyboy.com/2010/04/08/6-free-vector-seamless-backgrounds-source-files/。矢量纹理的好处是后期加工很方便。

还有就是纯CSS的层叠菜单。Google了很多,最后还是采用了http://purecssmenu.com/提供的代码。笔者针对自己的需要,砍掉了不少代码。

HTML源代码

早期版本的HTML、CSS、切图都可以在Google Code上找到,SVN地址如下:

https://evis-lab.googlecode.com/svn/themes/royalgold/src

《金光碧色》主题

主题为什么取这名字就不要深究了。

在上述HTML版本之后,笔者就将HTML代码合并到BlogEngine.NET的Standard主题中了,后来的开发、除错都是基于ASP.NET页面进行的。从结果来看,主题有如下特性。

  • 金色系配色;
  • 纯CSS(CSS2.1)布局,左右两栏,最窄780px、最宽1000px自适应,侧边栏宽度固定为300px;
  • 纯CSS层叠菜单;
  • 在IE7/8,Chrome,Maxthon2/3下测试通过;
  • 适用于BlogEngine.NET 2.0RC及2.0,之前版本尚未测试。

已知bug:

  • 在IE7/8下,Google广告之类的iframe内容会将弹出来的层叠菜单遮住;
  • 在IE7/8下,任何时间都会出现横向的滚动条。

最新版本的《金光碧色》主题可以从这里下载,解压缩至BlogEngine.NET相关目录即可使用。

如果有哪位朋友有兴趣将主题迁移到WordPress,同样请留言,笔者会提供相应支持。

后记

果然是自己从未尝试过的色系,看久了多少有点眼晕的感觉……

制作主题这种事情,笔者认为最舒服的还是做效果图的阶段。神马Web Standard,神马HTML5、CSS3,业界推广这么长时间了,想做个布局、加个边框之类的,开发量还是这么大,甚至避免不了CSS Hack。这么多年了,多浏览器兼容仍旧是个大问题。有时想想,还是表格布局来的畅快。还有,开发工具还是这么单薄……等等各种抱怨。

说回来,Web页面开发这类工作,还得是设计师和前端工程师合作来做,别太期待团队里出来一个英雄,从美工到前端,加上体验设计,甚至再到后端,把一个网站硬生生的扛下来。领域太广、细节太多、耗时太长。哦,笔者可没说自己是这样的人物。