Http Servlet Proxy

JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象,由于JavaScript同源策略的限制,a.com 域名下无法操作b.com或是c.a.com域名下的对象。

有一种特别的方法就是使用HTTP代理实现跨域访问iFrame

在Nginx中可以很方便的配置代理

server {
    listen 80 ;
    listen [::]:80  ipv6only=on;

    root /usr/share/nginx/html/typecho;
    index index.php index.html index.htm;

    server_name applehater.cn;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    location /map/{
        proxy_pass http://hahahha.com/map/;
    }

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

为了使计算处理尽量集成到应用中,可以使用Servlet去代理访问

    public static void proxy(HttpServletRequest httpServletRequest,
                             HttpServletResponse httpServletResponse,
                             String targetUrl,
                             String prefixPath) throws IOException {
        String requestUrl = targetUrl + httpServletRequest.getRequestURI().replace(prefixPath, "");
        Log.d(requestUrl);
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(requestUrl).build();
        Response response = client.newCall(request).execute();
        Headers headers = response.headers();
        for (String headerNameStr : headers.names()) {
            String headerValueStr = headers.get(headerNameStr);
            httpServletResponse.setHeader(headerNameStr, headerValueStr);
        }
        OutputStream os = httpServletResponse.getOutputStream();
        byte[] data = response.body().source().readByteArray().clone();
        os.write(data);
        os.flush();
        os.close();
    }

过程

                a.com/home             b.com/school               
+----------+               +-------+                 +-----------+
|          +-------------> |       +---------------> |           |
|          |               |       |                 |           |
| Browser  |               | Proxy |                 |  Server   |
|          |    Hello      |       |     Hello       |           |
|          | <-----------+ |       | <---------------+           |
+----------+               +-------+                 +-----------+

性能没有优化,比Nginx并发低好多。

cURL for Windows

https://curl.haxx.se/download.html

找到Win64 - Generic后下载归档文件。

解压到自己的软件目录,如C:\Tools\curl-7.49.1-win32-mingw

添加到环境变量Path变量值为可执行文件目录C:\Tools\curl-7.49.1-win32-mingw\bin

C:\Users\zonghua>curl cn.bing.com
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="zh" xml:lang="zh" xmlns="http://www.w3.org/1999/xhtml"><script type="text/javascript">//<![CDATA[
si_ST=new Date;
//]]></script><head><meta content="text/html; charset=utf-8" http-equiv="content-type"/><script type="text/javascript">//<![CDATA[
0;_G={ST:(si_ST?si_ST:new Date),Mkt:"zh-CN",RTL:false,Ver:"29",IG:"436629975B45473580C7CEE4D458B9C4",EventID:"1BEA8903F61A4B30B7EB7E9FC10B233C",V:"homepage",P:"SERP",DA:"HK2",CID:"1EB05C571F6267BB3B8C55021EC3663D",SUIH:"zqS4lpMPYcKolCxjyqhzCQ",gpUrl:"\/fd\/ls\/GLinkPing.aspx?" }; _G.lsUrl="/fd/ls/l?IG="+_G.IG+"&CID="+_G.CID ;curUrl="http:\/\/cn.bing.com\/";function si_T(a){ if(document.images){_G.GPImg=new Image;_G.GPImg.src=_G.gpUrl+'IG='+_G.IG+'&CID='+_G.CID+'&'+a;}return true;};...

类似PHP的curl扩展,可以封装一个Java的类库,cURL参数构造模板,文件上传下载使用缓存文件,进程ID防止锁。

自己动手来实现Dispatcher原理

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Controller {

}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Get {
    String value();
}

@Controller
class MyApplication {
    public static void main(String[] args) {
        SummerBootApplication.run(MyApplication.class);
    }

    @Get("/index")
    String index() {
        return "This is index page";
    }

    @Get("/about")
    String about() {
        return "A simple mvc showcases";
    }

}

public class SummerBootApplication {
    static Map<String, Object> bucket = new HashMap<String, Object>();
    static List<String> classFilePaths = new ArrayList<String>();
    static Map<String, Object> mappiing = new HashMap<String, Object>();

    static void readClassName(File file) {
        String fileName = file.getName();
        if (file.isFile() && fileName.endsWith(".class") && !fileName.contains("$")) {
            classFilePaths.add(file.getPath());
        } else if (file.isDirectory()) {
            File[] files = file.listFiles(new FilenameFilter() {
                public boolean accept(File dir, String name) {
                    if (name.endsWith(".class") && !name.contains("$")) {
                        return true;
                    } else {
                        return false;
                    }
                }
            });
            for (File fileItem : files) {
                readClassName(fileItem);//递归读取类文件
            }
        }
    }

    static void loadClass(String className) {
        Class<?> controllerClass = null;
        try {
            controllerClass = Class.forName(className);
            Controller controllerAnnotaion = controllerClass.getAnnotation(Controller.class);
            if (controllerAnnotaion != null) {
                Method[] methods = controllerClass.getDeclaredMethods();
                for (Method method : methods) {
                    Get getMethodAnnotaion = method.getAnnotation(Get.class);
                    if (getMethodAnnotaion != null) {
                        Object controllerObject = controllerClass.newInstance();
                        String getPath = getMethodAnnotaion.value();
                        bucket.put(className, controllerObject);
                        mappiing.put(getPath, className + "@" + method.getName());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void response(String message) {
        System.out.println(message);
    }

    static void dispatcher(String path) {
        Set<String> keySet = mappiing.keySet();
        boolean isNotFound = true;
        for (String matchPath : keySet) {//这里使用了最简单的线性搜索
            if (path.startsWith(matchPath)) {//直接判断路径匹配,或者可以使用正则
                isNotFound = false;
                String controllerClassNameAndMethodName = (String) mappiing.get(matchPath);
                String[] names = controllerClassNameAndMethodName.split("@");
                String controllerClassName = names[0];
                String methodName = names[1];
                handle(controllerClassName, methodName);//后续可以给handle传入请求对象
            }
        }
        if (isNotFound) {
            System.out.println("404");
        }
    }

    public static void handle(String controllerClassName, String methodName) {
        Object controller = getBean(controllerClassName);
        Class<?> controllerClass = controller.getClass();
        try {
            Method handleMethod = controllerClass.getDeclaredMethod(methodName);
            Class<?> returnType = handleMethod.getReturnType();
            Object returnObject = handleMethod.invoke(controller);//调用处理方法
            response(returnObject.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    static void fillBucket(String rootFilePath, String classPath) {
        classPath = classPath.replace("/", "\\").substring(1, classPath.length() - 1);
        File rootFile = new File(rootFilePath);
        readClassName(rootFile);
        for (String classFilePath : classFilePaths) {
            String className = classFilePath.replace(classPath, "")
                    .replace(".class", "")
                    .replace("\\", ".");
            className = className.substring(1, className.length());
            loadClass(className);
        }
    }

    public static void run(Class clazz) {
        String rootFilePath = clazz.getResource("").getFile();
        String classPath = clazz.getClassLoader().getResource("").getPath();
        fillBucket(rootFilePath, classPath);
        Scanner scanner = new Scanner(System.in);
        System.out.println("Winter Boot application listening");
        while (true) {
            String path = scanner.nextLine();
            if (path.equals("bye")) {
                break;
            }
            dispatcher(path);
        }
    }

    public static Object getBean(String className) {
        return bucket.get(className);//通过其他设置,可以实现懒加载或者多次实例化而不是单例
    }
}

运行结果,匹配路径在控制台输入做演示

Winter Boot application listening
/index
This is index page
/about
A simple mvc showcases
/about?page=3
A simple mvc showcases
/sdhfsdhf
404