安卓Webview:禁用CORS

26

Android允许本机应用程序禁用CORS安全策略,以进行http://(非本地/文件)请求吗?

在我的本机应用程序中,Webview通过http://显示远程HTML,而不是在本地/文件系统上。这似乎在与Web浏览器内部相同的方式下受到CORS限制。

解决方法:用于ajax请求的本机-js桥接跨域,这些域没有Access-Control-Allow-Origin:*是我的快速'n'dirt解决方案。(jsonp或服务器端代理不是一个选项,因为WebService检查客户端的cookie + ip)

是否可以禁用该策略以供应用程序内部的Webview使用?

请让我知道,如果有一个简单的标志允许js绕过此限制,限制“本地”应用程序的Webview。

3个回答

19

自Android API 21级起,现在可以实现此功能。您可以像这样创建OPTIONS响应:

public class OptionsAllowResponse {
    static final SimpleDateFormat formatter = new SimpleDateFormat("E, dd MMM yyyy kk:mm:ss", Locale.US);

    @TargetApi(21)
    static WebResourceResponse build() {
        Date date = new Date();
        final String dateString = formatter.format(date);

        Map<String, String> headers = new HashMap<String, String>() {{
            put("Connection", "close");
            put("Content-Type", "text/plain");
            put("Date", dateString + " GMT");
            put("Access-Control-Allow-Origin", /* your domain here */);
            put("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS");
            put("Access-Control-Max-Age", "600");
            put("Access-Control-Allow-Credentials", "true");
            put("Access-Control-Allow-Headers", "accept, authorization, Content-Type");
            put("Via", "1.1 vegur");
        }};

        return new WebResourceResponse("text/plain", "UTF-8", 200, "OK", headers, null);
    }
}

然后在您的WebViewClient实现中调用它,如下所示:

    @Override
    @TargetApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        if (request.getMethod().equalsIgnoreCase("OPTIONS")) {
            return OptionsAllowResponse.build();
        }

        return null;
    }

由于OPTIONS响应需要检查WebResourceRequest中请求的HTTP方法,而该方法只在API 21及以上版本中提供,因此仅适用于API级别21以上的版本。


3
我不认为这会禁用CORS,它只是拦截请求并返回你想要的内容,而不是实际的请求数据。 - jcesarmobile
4
你说得没错,它不直接处理GET/PUT/POST请求的请求数据,但是CORS涉及到两个请求:第一个是没有请求数据的HTTP OPTIONS请求,用于检查是否可以进行GET/PUT/POST请求,如果可以,WebView将继续使用数据进行实际请求。这段代码覆盖了第一个OPTIONS请求的响应,以便第二个请求可以通过。 - davidgoli
你如何从JavaScript中发出请求?在我的测试中,我从未收到OPTIONS请求,只有实际失败的请求,因此我最终使用了HttpURLConnection来获取文件数据并将其返回到WebResourceResponse中。 - jcesarmobile
@davidgoli 你有什么办法可以解决我在使用POST请求时遇到的REACT-NATIVE问题吗?请参见https://stackoverflow.com/questions/52178543/invalid-cors-request-error-in-webview-used-in-react-native - Yossi
当使用<iframe>时,从未看到OPTIONS请求。 - Yeung
显示剩余5条评论

12

据我所知,这是不可能的,相信我,我已经尝试了许多方法。

你能做的最好的事情就是覆盖资源加载。请参见从WebView拦截和覆盖HTTP请求


抱歉再次询问。自API 11以来,通过操纵标头响应始终接受CORS,这不能通过shouldInterceptRequest进行“修复”吗? - ledy
可以的,见下面我的回答。 - davidgoli
@MarcoMartinelli 你有什么办法可以解决我在使用POST请求时遇到的REACT-NATIVE问题吗?请参见https://stackoverflow.com/questions/52178543/invalid-cors-request-error-in-webview-used-in-react-native - Yossi

-1

我使用C#和Xamarin时,发现下面的简短版本对我很有帮助:

    public override WebResourceResponse ShouldInterceptRequest(WebView view, IWebResourceRequest request)
    {
        if (request.Url.SchemeSpecificPart.StartsWith("//<domain>/"))
        {
            request.RequestHeaders.Add("Access-Control-Allow-Origin", "*");
        }

        return base.ShouldInterceptRequest(view, request);
    }

此覆盖是针对 Android.Webkit.WebViewClient 进行的,其中<domain> 是被 CORS 策略阻止的域名。


3
CORS头应该在响应中,而不是请求中。 - noe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接