Meego走了,Tizen来了

MeeGo 官方发布公告,MeeGo 结束了。

https://meego.com/community/blogs/imad/2011/whats-next-meego

What’s Next for MeeGo
Submitted by Imad Sousou on 27 September, 2011 – 21:01
By now, you may have read that The Linux Foundation, with the support of several other companies, announced a new project, Tizen, to build a new operating system for devices. This new project is first and foremost open source, and based on Linux. So it begs the question: why not just evolve MeeGo? We believe the future belongs to HTML5-based applications, outside of a relatively small percentage of apps, and we are firmly convinced that our investment needs to shift toward HTML5. Shifting to HTML5 doesn’t just mean slapping a web runtime on an existing Linux, even one aimed at mobile, as MeeGo has been. Emphasizing HTML5 means that APIs not visible to HTML5 programmers need not be as rigid, and can evolve with platform technology and can vary by market segment.

Granted, this is a judgment on our part on which reasonable people could disagree, but that’s the conclusion I came to.

But in the new project, a lot of things will be the same as they were in the MeeGo project. The Tizen project will reside within the Linux Foundation, will be governed by a Technical Steering Group, and will be developed openly with familiar and improved infrastructure. Much like MeeGo, the Tizen project will support multiple device categories, including Tablets, Netbooks, Handsets, Smart TV, and In-Vehicle Infotainment systems.

Over the next couple of months, we will be working very hard to make sure that users of MeeGo can easily transition to Tizen, and I will be working even harder to make sure that developers of MeeGo can also transition to Tizen.

I want to personally thank everyone who has participated in MeeGo over the past year and a half, and I encourage you to join us at Tizen.org. We hope to use what we learned from the MeeGo project to make Tizen successful, and I hope to see you participating in Tizen!

Imad

Linux Foundation 重新开始了一个名为 Tizen的项目,开源而且是基于Linux内核的操作系统。他们认为未来的操作系统是大都基于HTML5 的网络应用,以后只会保留其中的一小部分。现在他们需要确保当前在 MeeGo 上的努力可以顺利迁移到新的 Tizen 项目上。而 Tizen 绝大部分东西都是与 MeeGo 项目共用。Tizen 和 MeeGo 一样都是由 Linux Foundation 管理,而技术上是由一个技术委员会控制,未来会在一个更加友好更加开放的框架下开发。当然,Tizen 也是面向平板电脑,上网本,手持设备,智能电视和车载设备多种设备。

MeeGo社区感谢每一个关心和支持 MeeGo 项目的朋友。他们仍然为提供方案给用户迁移到新的 Tizen 上。最后呼吁 MeeGo 的爱好者和开发者积极参与到新的 Tizen 项目。

看到这则消息,已经没有太大的情感起伏了,好像早预料到这一天似的,只能说,meego很优秀,只是缺了好爹娘。

感兴趣的,可以去看看 https://www.tizen.org/,虽然meego错过了好时机,不过当下对于html5来说,一切还刚刚开幕。祝福tizen。

python3.2.2增加了一个新的并发库

http://www.python.org/dev/peps/pep-3148/

用过java并发框架的人可能看过后就乐了.

这个库很精简,主要有两个核心类: Executor and Future,Executor用来接收异步任务(包含参数),并返回一个Future.

Executor

submit(fn, *args, **kwargs)
map(func, *iterables, timeout=None)
shutdown(wait=True)

Executor还有两个子类ThreadPoolExecutor,ProcessPoolExecutor

Future Objects

cancel()
cancelled()
running()
done()
result(timeout=None)
exception(timeout=None)
add_done_callback(fn)

看两个例子:
Check Prime Example

from concurrent import futures
import math

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    with futures.ProcessPoolExecutor() as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime,
                                                      PRIMES)):
            print('%d is prime: %s' % (number, prime))

if __name__ == '__main__':
    main()

Web Crawl Example

from concurrent import futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

def load_url(url, timeout):
    return urllib.request.urlopen(url, timeout=timeout).read()

def main():
    with futures.ThreadPoolExecutor(max_workers=5) as executor:
        future_to_url = dict(
            (executor.submit(load_url, url, 60), url)
             for url in URLS)

        for future in futures.as_completed(future_to_url):
            url = future_to_url[future]
            try:
                print('%r page is %d bytes' % (
                          url, len(future.result())))
            except Exception as e:
                print('%r generated an exception: %s' % (
                          url, e))

if __name__ == '__main__':
    main()

非主流 java web开发-权限控制篇 (六)

一般情况下,最长间的是用户权限和管理员权限控制,我们可以定义两个元注释和封装一个action来解决问题,

package org.xhttpd.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target( { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthUser {

}
package org.xhttpd.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target( { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthAdmin {

}
package org.xhttpd.actions;

import java.io.IOException;

import org.xhttpd.annotation.AuthAdmin;
import org.xhttpd.annotation.AuthUser;
import org.xlightweb.BadMessageException;
import org.xlightweb.IHttpExchange;
import org.xlightweb.IHttpRequest;
import org.xlightweb.IHttpRequestHandler;
import org.xlightweb.IHttpSession;

public abstract class FliterAction implements IHttpRequestHandler {

    public void onRequest(IHttpExchange http) throws IOException, BadMessageException {

        IHttpRequest req = http.getRequest();
        req.setHeader("Content-Type", req.getContentType() + "; charset=UTF-8");
        IHttpSession session = http.getSession(true);
        if (this.getClass().getAnnotation(AuthAdmin.class) != null) {

            if (session.getAttribute("admin") == null) {
                http.sendRedirect("/admin/login");
                return;
            }
        }
        if (this.getClass().getAnnotation(AuthUser.class) != null) {

            if (session.getAttribute("user") == null) {
                http.sendRedirect("/");
                return;
            }
        }

        if (req.getMethod().toLowerCase().equals("get"))
            doGet(http);
        else if (req.getMethod().toLowerCase().equals("get"))
            doPost(http);
        else
            doPost(http);

    }

    public abstract void doGet(IHttpExchange http) throws IOException, BadMessageException;

    public abstract void doPost(IHttpExchange http) throws IOException, BadMessageException;
}

在action实例中加上元注释即可

package org.xhttpd.actions;

import java.io.IOException;

import org.xhttpd.annotation.AuthUser;
import org.xhttpd.common.Freemarker;
import org.xlightweb.BadMessageException;
import org.xlightweb.IHttpExchange;
import org.xlightweb.Mapping;
@AuthUser
@Mapping("/*")
public class IndexAction extends FliterAction{

    private Freemarker free;

    public void setFree(Freemarker free) {
        this.free = free;
    }

    @Override
    public void doGet(IHttpExchange http) throws IOException, BadMessageException {
        // .....
        http.getRequest().setAttribute("name", "jamiesun");
        http.send(free.render(http, "index"));

    }

    @Override
    public void doPost(IHttpExchange http) throws IOException, BadMessageException {
        // TODO Auto-generated method stub
    }

}

通过这种机制,在更复杂业务场景中,通过有效的封装一样可以解决更细粒度的权限控制。

非主流 java web开发-模板篇 (五)

在这个框架中,用jsp来做页面展示是没有什么可能了,开源的模板freemarker自然是手到擒来,这是我非常中意的一个工具。

package org.xhttpd.common;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.picocontainer.Startable;
import org.xhttpd.annotation.Inject;
import org.xlightweb.HttpResponse;
import org.xlightweb.IHttpExchange;
import org.xlightweb.IHttpResponse;

import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;

@Inject
public class Freemarker implements Startable {
    private final static Log log = LogFactory.getLog(Freemarker.class);
    private Configuration cfg;
    private Config config;
    private Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    public void setConfig(Config config) {
        this.config = config;
    }

    public void start() {
        try {
            cfg = new Configuration();
            cfg.setDirectoryForTemplateLoading(new File("templates"));
            cfg.setTemplateUpdateDelay(0);
            cfg.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
            cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
            cfg.setDefaultEncoding("utf-8");
            cfg.setLocale(Locale.CHINESE);
            cfg.setSharedVariable("sitename", config.getString("site.name"));
            cfg.setSharedVariable("sitebase", config.getString("site.base"));
            cfg.setSharedVariable("context", context);

        } catch (Exception e) {
            log.error("freemarker init error", e);
        }

    }

    public void stop() {

    }

    @SuppressWarnings( { "unchecked" })
    public IHttpResponse render(IHttpExchange http, String tmpname) {

        IHttpResponse resp = null;
        try {
            Template tmp = cfg.getTemplate(tmpname + ".html");

            Writer out = new StringWriter();

            Map content = new HashMap();

            for (String name : http.getRequest().getAttributeNameSet()) {
                content.put(name, http.getRequest().getAttribute(name));
            }
            content.put("session", http.getSession(true));
            tmp.process(content, out);

            String body = out.toString();

            resp = new HttpResponse("text/html", body.getBytes("utf-8"));

        } catch (Exception e) {
            log.error("template file render error " + tmpname, e);
            try {
                resp = new HttpResponse(500, e.getMessage());
            } catch (IOException e1) {
            }

        }
        return resp;
    }

    public String render(String tmpname, Map content) {

        try {

            Template tmp = cfg.getTemplate(tmpname + ".html");

            Writer out = new StringWriter();

            tmp.process(content, out);

            String body = out.toString();

            return body;

        } catch (Exception e) {

            log.error("template file render error " + tmpname, e);

        }
        return null;
    }

}

这是一个freemarker组件的封装,顺便basession也放进去了,里面还有一个Context组件,很普通的一个类

package org.xhttpd.common;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import org.xhttpd.annotation.Inject;

@Inject
public class Context {

    public Context() {
        // TODO Auto-generated constructor stub
    }

    public String substr(String src, int len) {
        if (src == null)
            return null;
        if (src.length() < = len)
            return src;

        return src.substring(0, len - 1);
    }

    public String subhtml(String src, int len) {
        if (src == null)
            return null;
        src = Utils.Html2Text(src);
        if (src.length() <= len)
            return src;

        return src.substring(0, len - 1);
    }

    public String encodeUrl(String src) {
        if (src == null)
            return null;
        try {
            return URLEncoder.encode(src, "utf-8");
        } catch (UnsupportedEncodingException e) {
            return src;
        }
    }

}

如何使用?

package org.xhttpd.actions;

import java.io.IOException;

import org.xhttpd.common.Freemarker;
import org.xlightweb.BadMessageException;
import org.xlightweb.IHttpExchange;
import org.xlightweb.IHttpRequestHandler;
import org.xlightweb.Mapping;

@Mapping("/*")
public class IndexAction implements IHttpRequestHandler {

    private Freemarker free;

    public void setFree(Freemarker free) {
        this.free = free;
    }

    @Override
    public void onRequest(IHttpExchange http) throws IOException, BadMessageException {
        // .....
        http.getRequest().setAttribute("name", "jamiesun");
        http.send(free.render(http, "index"));
    }

}

freemarker的使用就不讲了,官方有很详细的文档,中文的也有,这里的模板也就是一个html页面,显示name值只需要用${name}即可。

因为依赖注入功能的存在,setFree方法是不需要你去手工调用的。

非主流 java web开发-组件篇 (四)

在前一篇中,你可能已经发现了在Config类中,多了一个@Inject,明眼人立即看出这不就是个java元注解嘛,是的,这没啥奇怪的,不过这是个很重要得注释,用上了这个标记表示他是一个组件,是要被塞进Beans容器的,同时可以享受到依赖注入的好处。

Config是一个组件,处理请求的IWebHandler实例也是组件,还可能又更多各种各样的组件,甭管啥组件,统统扔进Beans里去管理。

下面是一个主框架的入口类,在这个类中,Beans容器装入并初始化所有组件,启动服务器。

package org.xhttpd;

import java.util.HashSet;

import org.apache.log4j.xml.DOMConfigurator;
import org.xhttpd.annotation.Inject;
import org.xhttpd.common.ActionSet;
import org.xhttpd.common.Beans;
import org.xhttpd.common.Config;
import org.xhttpd.common.Utils;
import org.xlightweb.Mapping;

public class Main {
	public static void main(String[] args) throws Exception {
	    DOMConfigurator.configure("conf/log4j.xml");
	    HashSet CLASSES = Utils.loadClasses("org.xhttpd");
	    ActionSet actionSet = new ActionSet();

	    for (Class clasz : CLASSES) {
			if(clasz.getAnnotation(Inject.class)!=null)
			{
				Beans.put(clasz);
			}
			if(clasz.getAnnotation(Mapping.class)!=null)
			{
				Beans.put(clasz);
				actionSet.add(clasz);
			}
		}
	    Beans.start();
	    new Server().start(Beans.getBean(Config.class),actionSet);

	}
}

这个类设计的不够好,Server实际上应该作为组件放入Beans里的,因为我碰到了一个问题,使用picocontainer提供的组件生命周期管理的一个问题。

picocontainer提供的生命周期管理,典型的是实现一个startable接口,实现接口提供的start,stop方法即可,容器调用start时可以调用容器中所有实现此接口的start方法,stop也是。但是在start的过程中,是不能同时获取容器中的组件的,涉及到线程安全问题,我觉得深入看看源代码应该可以解决,不过这里我偷了一下懒。

Utils.loadClasses(“org.xhttpd”);这个工具方法载入所有类,然后把Inject和Mapping标注过得类全部装入容器。

Beans.start();启动所有实现startable的组件。

Mapping是xlightweb中的元注解,有一个字符串参数,主要用在处理请求的action类中,比如:

package org.xhttpd.actions;
import java.io.IOException;
import org.xlightweb.BadMessageException;
import org.xlightweb.IHttpExchange;
import org.xlightweb.IHttpRequestHandler;
import org.xlightweb.Mapping;

@Mapping("/index")
public class IndexAction implements IHttpRequestHandler{
	@Override
	public void onRequest(IHttpExchange exchange) throws IOException,
			BadMessageException {

	}
}

一看就知道实干什么的了。

非主流 java web开发-服务器篇 (三)

现在该是把服务器架起来的时候了,xlightweb上场了,http协议封装就交给它了,请求分发也交给它了,

package org.xhttpd;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xhttpd.common.ActionSet;
import org.xhttpd.common.Beans;
import org.xhttpd.common.Config;
import org.xlightweb.Context;
import org.xlightweb.IWebHandler;
import org.xlightweb.server.HttpServer;
import org.xsocket.connection.IConnection.FlushMode;

public class Server{

    private final static Log log = LogFactory.getLog(Server.class);
    private HttpServer hsrv = null;

    static class ServerThreadFactory implements ThreadFactory {
    	private static AtomicInteger number = new AtomicInteger(0);
        public Thread newThread(Runnable r) {
            return new Thread(r, "Server-Workerpool-Thread-"+ number.incrementAndGet());
        }

    }

	@SuppressWarnings({ "unchecked" })
	public void start(Config config,ActionSet actionSet) {
        try {
            Context rootCtx = new Context("");
    	    for (Class clasz : actionSet) {
    	    	IWebHandler action =  (IWebHandler) Beans.getBean(clasz);
    			rootCtx.addHandler(action);
    		}
            System.setProperty("org.xlightweb.showDetailedError", "true");

            hsrv = new HttpServer(config.getInt("http.port", 9000), rootCtx);
            hsrv.setWorkerpool(Executors.newCachedThreadPool(new ServerThreadFactory()));
            hsrv.setMaxConcurrentConnections(config.getInt("http.maxConn", 1024));
            hsrv.setAutoCompressThresholdBytes(2048);
            hsrv.setFlushmode(FlushMode.ASYNC);

            hsrv.setAutoUncompress(true);
            hsrv.setConnectionTimeoutMillis(600*1000);
            hsrv.setBodyDataReceiveTimeoutMillis(300*1000);
            hsrv.setRequestBodyDefaultEncoding("utf-8");
            hsrv.setStartUpLogMessage("server starting...");
            hsrv.start();
            log.info("server start.....");
        } catch (Exception e) {
            log.error("server start fail", e);
        }
	}
}

这个实例实在浅显,不需要多解释,不过需要提一下两个参数:

Config config,系统配置类,对应的类和配置文件为

package org.xhttpd.common;
import java.io.FileInputStream;
import java.util.Properties;
import org.xhttpd.annotation.Inject;

@Inject //这个注释是干嘛的
public class Config {

    private Properties cfg;

    public Config() throws Exception {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("conf/config.xml");
            cfg = new Properties();
            cfg.loadFromXML(fis);
        } finally {
            if (fis != null)
                fis.close();
        }
    }

    public int getInt(String key) {
        return Integer.parseInt(cfg.getProperty(key));
    }

    public int getInt(String key, int defaultValue) {
        return Integer.parseInt(cfg.getProperty(key, String
                .valueOf(defaultValue)));
    }

    public String getString(String key) {
        return cfg.getProperty(key);
    }

    public String getString(String key, String defaultValue) {
        return cfg.getProperty(key, defaultValue);
    }

}


< ?xml version="1.0" encoding="UTF-8"?>
< !DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

http config
9090
10000

ActionSet actionSet

看名字知道这是一堆action/handle的集合,和struts里的action是一个概念,这里要把它们注册到server里去,每一个http请求都可以分发道义个action去处理。

这里的action是xlightweb里IWebHandler接口的实例,后面会讲到。

所有的action都是从Beans里取出来的,很显然,之前他们都被扔到Beans里去了。

非主流 java web开发-DI容器篇 (二)

在搭建起服务器前,先要搞定一个DI容器,这是整个框架的基础,但是这里的DI容器是一个简单到不能再简单的玩意,这恰恰就是我的目的,解决组件之间的依赖,同时仅仅用到了set注入。

package org.xhttpd.common;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.defaults.CachingComponentAdapterFactory;
import org.picocontainer.defaults.DefaultPicoContainer;
import org.picocontainer.defaults.SetterInjectionComponentAdapterFactory;
import org.picocontainer.defaults.VerifyingVisitor;

/**
 * @author @jamiesun
 */
public class Beans {
	private final MutablePicoContainer pico = new DefaultPicoContainer(
			new CachingComponentAdapterFactory(
					new SetterInjectionComponentAdapterFactory()));
	private final static Beans beans = new Beans();
	private final static Log log = LogFactory.getLog(Beans.class);

	private Beans() {
	}

	public static Beans getInstance() {
		return beans;
	}

	public void registryBean(Class clasz) {
		if (pico.getComponentInstanceOfType(clasz) != null)
			return;
		pico.registerComponentImplementation(clasz);
		log.info("registry [" + clasz.getName() + "] done !");
	}

	public void registryBean(Object obj) {
		pico.registerComponentInstance(obj);
		log.info("registry [" + obj.getClass().getName() + "]  done !");
	}

	public void startAll() {
		new VerifyingVisitor().traverse(pico);
		pico.start();
	}

	public void stopAll() {
		pico.stop();
	}

	public void dispose() {
		pico.dispose();
	}

	@SuppressWarnings("unchecked")
	public  T get(Class clasz) {
		return (T) pico.getComponentInstanceOfType(clasz);
	}

	public static  T getBean(Class clasz) {
		return getInstance().get(clasz);
	}

	public static void put(Class cs) {
		getInstance().registryBean(cs);
	}

	public static void put(Object obj) {
		getInstance().registryBean(obj);
	}

	public static synchronized void start() {
		getInstance().startAll();
	}

	public static void stop() {
		getInstance().stopAll();
	}

	public String toString() {
		return pico.toString();
	}

}

非主流 java web开发-介绍 (一)

在网上搜索变形金刚,无意看到牛人DIY的变形金刚,确实感到很震撼.
牛人自制变形金刚

话说写java这么多年,却极少用struts,spring,webwork,habnate等.近5年几乎都没有在项目中碰这些玩意,在这个言必出框架,架构的时代,我是有点落伍了.不过现在也得说句,不用这些玩意就做不了”企业应用”吗.非也.在实际项目中,基本上是根据实际情况来定制各个业务组件的,如web容器,依赖注入,数据访问,远程调用,TCP接口.

在写java的几年里,也同时不遗余力的学习python,两种不同的语言两种不同的编程思想很折磨人,不过后来,我确实是更偏爱python了.

下面要写的是我个人一个的一点实践,完全避开”主流”的tomcat,struts,spring,随手捡的几个开源组件,随意拼凑出一个web应用,顺便说一句.

一,socket,xlightweb

xsocket是一个轻量级的NIO框架,核心思想是简化nio方式的的开发,不需要过多的学习,这一点很重要,我不喜欢一堆的文档,碰到问题按一下F4直接去看源码省事多了.xlightweb则是xsocket的衍生品,基于xsocket的一个web服务器,同样简单,他的文档只有一页,但是基本上看过就掌握的差不多了,我就喜欢这样的,人生苦短,文档少看.

在应用中,xlightweb是用来代替tomcat作为嵌入式容器的,最初也考虑jetty,不过jetty的新版本是变得越来越复杂了,遂放弃.如果你要让你的开发更简单,你就应该避免碰那些一堆文档死复杂的家伙.

二,picocontainer

picocontainer是一个简洁的依赖注入容器,这里主要是用来代替spring的,虽然xsocket有和spring整合的例子,不过这里不选spring,spring的东西太多,虽然可以只用spring的核心,但核心也仍然重了.

三,mongodb

这个就不用多说了吧,当下红的发紫的nosql,这里主要是代替habnate之类的orm,代替关系数据库.在java中使用mongodb应该避免引入第三方的过于复杂的封装,那些第三方的组件,我没有一一考察过,这里说不上什么,实际上基于mongodb java驱动的DBObject已经很简单了,如果你不愿意基于哈希表编程,你可以继承内置的ReflectionDBObject,这是一个简单的包装器,可以自动转换model里的字段到mongodb数据结构.但是也有不好的地方,它是根据set和get方法来截取字段的,每个字段首字母是大写,实在搞不懂mongodb java驱动开发人员为什么这样做,我能想到的原因就是:他懒.这个对象仅仅是告诉你一个解决问题的思路.

待续….

使用java scribe库进行新浪微博oauth认证的一个问题

java方面,scribe库非常简洁好用,不过在对新浪微博进行认证的时候,却发现设置回调url不起作用.

	OAuthService service = new ServiceBuilder()
        .provider(SinaWeiboApi.class)
        .apiKey("xxxx")
        .apiSecret("xxxx")
        .callback(req.getRequestUrl().toString())
        .build();

通过firebug跟踪发现,参数中的oauth_callback竟然是none,于是简单的在AuthorizationUrl后面加上了这个参数,结果没有问题,授权能跳转回来了.

http.sendRedirect(service.getAuthorizationUrl(requestToken)+"&oauth_callback="+req.getRequestUrl().toString());

在调用google,twitter的服务时没有这种问题,看来新浪是塞了点自己的东西,在google上搜索了一下,发现有一篇分析很透彻的文章,分享一下:随便写写oauth

Twisted Web代码示例

twisted.web.client

getpage.py - 使用twisted.web.client.getPage 下载页面.
dlpage.py -在下载页面过程中增加一个回调函数到twisted.web.client.downloadPage 用来显示错误信息

XML-RPC

xmlrpc.py XML-RPC 服务器的几个方法 包括 echoing, faulting, returning deferreds 以及 failed deferreds
xmlrpcclient.py - 使用 twisted.web.xmlrpc.Proxy来调用远程XML-RPC方法.
advogato.py – 使用twisted.web.xmlrpc添加日志到advogato.org,需要一个advogato.org帐号.

虚拟主机和代理

rootscript.py – twisted.web.vhost.NameVirtualHost的例子
web.py – 使用twisted.web.vhost.VHostMonsterResource作为反向代理处理某些特定文件.
proxy.py -使用twisted.web.proxy把任何http请求通过代理端口转发到指定网站

hello.rpy.py - 使用twisted.web.static创建一个静态资源服务
fortune.rpy.py - 创建一个返回服务器运行进程输出的资源
lj.rpy.py - 使用twisted.web.microdom,twisted.web.domhelpers和回调链来提取显示一个LiveJournal用户的RSS页面.
vhost.rpy.py - 创建一个twisted.web.vhost.VHostMonsterResource资源

report.rpy.py - 显示一个资源的各种属性,包括路径,主机和端口.
users.rpy.py - 使用 twisted.web.distrib 发布一个“社区网站”的用户目录
simple.rtl – 使用 twisted.web.resource.ResourceTemplate的模板示例

杂项

webguard.py -使用twisted.cred 来对twisted.web进行验证防止未授权的用户访问.
silly-web.py - 使用wisted.web.distrib and twisted.spread.pb发布一个最基本的主从模型的分布式网站.
google.py - 使用twisted.web.google获取我的手气不错的搜索页
soap.py – 使用 twisted.web.soap 发布SOAP方法.

来源:http://twistedmatrix.com/documents/current/web/examples/#auto0