JSONP 和 CORS 两种跨域方法

jsonp web 端代码:

        var $jsonp = (function(){
            var that = {};
            that.script = document.createElement('script');
            that.send = function(src, options) {
                var callback_name = options.callbackName || 'callback',
                on_success = options.onSuccess || function(){},
                on_timeout = options.onTimeout || function(){},
                on_error = options.onError || function(){},
                on_load = options.onLoad || function(){},
                timeout = options.timeout || 10; // sec
                var timeout_trigger = window.setTimeout(function(){
                    window[callback_name] = function(){};
                    that.clear();
                    on_timeout();
                }, timeout * 1000);
                window[callback_name] = function(data){
                    window.clearTimeout(timeout_trigger);
                    that.clear();
                    on_success(data);
                };
                that.script.type = 'text/javascript';
                that.script.async = true;
                that.script.src = src;
                that.script.onload = function() { 
                    that.clear(); 
                    window.clearTimeout(timeout_trigger);
                    on_load(); 
                };
                that.script.onerror = function() { 
                    that.clear(); 
                    window.clearTimeout(timeout_trigger);
                    on_error(); 
                };
                document.getElementsByTagName('head')[0].appendChild(that.script);
            }
            that.clear = function() {
                if (that.script.parentNode) {
                    that.script.parentNode.removeChild( that.script );
                }
            }

            return that;
        })();

        $jsonp.send('http://localhost/jsonp?callback=callbackfunc', {
            callbackName: 'callbackfunc',
            onSuccess: function(json){
                console.log('jsonp success!', json);
            },
            onTimeout: function(){
                console.log('jsonp timeout!');
            },
            onError: function(){
                console.log("jsonp on error");
            },
            onLoad: function(){
                console.log("jsonp on load");
            },
            timeout: 1
        });

后端接口 http://localhost/jsonp?callback=callbackfunc 返回内容:

Content-Type: application/javascript; charset=utf-8
Body:
callbackfunc({"name":"kyle","version":"1.0"});

cors 方法前端代码:

       var $cors = (function(){
            var that = {};
            that.send = function(url, method, data, options) {
                on_success = options.onSuccess || function(xhr){},
                on_timeout = options.onTimeout || function(){},
                on_error = options.onError || function(){},
                on_load = options.onLoad || function(){},
                timeout = options.timeout || 10; // sec

                var xhr = new XMLHttpRequest();
                if ("withCredentials" in xhr) {
                    xhr.open(method, url, true);
                }else if(typeof XDomainRequest != "undefined") {
                    xhr = new XDomainRequest();
                    xhr.open(method, url);
                }else{
                    // CORS not supported.
                    xhr = null;
                };

                if (!xhr) {
                    return false;
                };
                xhr.timeout = timeout * 1000;
                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
                xhr.onload = function() {
                    on_success(xhr);
                };
                xhr.onerror = function() { on_error(); };
                xhr.onprogress = function () { };
                xhr.ontimeout = function () {  on_timeout(); };
                setTimeout(function () { xhr.send(data); }, 0);
                return true;
            }
            return that;
        })();

        ret = $cors.send("http://localhost/cors", "post", "task=123456", {
            onSuccess: function(json){
                console.log('cors success!', json);
            },
            onTimeout: function(){
                console.log('cors timeout!');
            },
            onError: function(){
                console.log("cors on error");
            },
            onLoad: function(){
                console.log("cors on load");
            },
            timeout: 2
        });

        if(!ret) {
            alert("cors not supported.");
        }

后端接口 http://localhost/cors 返回内容:

Access-Control-Allow-Methods: POST, OPTIONS, GET, PUT
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Access-Control-Allow-Origin
Content-Type: text/plain; charset=utf-8

主要返回以上这些头部。XDomainRequest 是为了兼容 IE8。

如果不是简单请求,浏览器可能会请求 OPTIONS 方法,后端也要实现该方法,返回上面的头部。以 gin 框架示例代码如下:


func CorsTask(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Expose-Headers", "Access-Control-Allow-Origin") c.Header("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT") c.Header("Control-Allow-Credentials", "false") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.String(http.StatusOK, "yes") } router := gin.Default() router.POST("/addtask", CorsTask) router.OPTIONS("/addtask", CorsTask)