背景:
我们访问的服务器可能要访问其他服务器的文件, 例如我们将文件存储到阿里云, 自己的服务器只缓存对应的url地址。 如果我们的服务器上部署个H5页, H5要显示阿里云的图片, 这时就遇到了跨域问题。 JavaScript默认只能访问同源的文件。
同源策略是浏览器最重要的一种安全机制,由Netscape于1995年最先提出,现在的主流浏览器都遵循这种策略。同源一般指协议,域名,端口都相同,但IE浏览器会忽略对端口的判断。RFC 6454定义了计算同源URL的算法。为了形象的描述同源URL,下表给出了特定URL是否与http://www.360.cn/weishi/index.html同源的计算结果和原因。
被比较的URL |
比较结果 |
原因 |
http://www.360.cn/index.html |
同源 |
协议和域名都相同 |
http://www.360.cn/weishi/updatelog.html |
同源 |
协议和域名都相同 |
http://360.cn/index.html |
非同源 |
域名不同 |
http://shouji.360.cn/index.html |
非同源 |
域名不同 |
http://www.360.cn:8088/index.html |
非同源 |
端口不同 |
https://www.360.cn |
非同源 |
协议不同 |
http://www.google.com |
非同源 |
域名不同 |
file:///C:/Program%20Files/360/ |
非同源 |
协议与域名都不相同 |
JavaScript在访问非同源(即跨域)对象时, 浏览器会因为安全原因拒绝掉。
例如访问地址: http://123.124.21.142:8081/PDFWJDemo/web/readPdf.html?file=http://10.0.4.220:80/group2/M00/01/44/wKgBMVgES2yAdfH-AAGokQ7w640603.pdf&size=2&certpswd=MTExMTEx&contractseq=1
http://123.124.21.142:8081/PDFWJDemo/web/readPdf.html是个H5页, 要下载http://10.0.4.220:80/group2/M00/01/44/wKgBMVgES2yAdfH-AAGokQ7w640603.pdf&size=2&certpswd=MTExMTEx&contractseq=1。
因为跨域了,默认无法下载对应的文件。 使用浏览器打开上述链接会提示CORS头缺少Access-Control-Allow-Origin。
PS:上图用的是FireFox浏览器的插件FireBug。
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS 详情讲述了访问控制的原则。 实际上我们只需要在Http返回头添加Access-Control-Allow-Origin:*就可以了
Http返回头:
HTTP/1.1 200 OK
Server: openresty/1.5.8.1
Date: Mon, 17 Oct 2016 12:53:56 GMT
Content-Type: application/pdf
Content-Length: 108689
Connection: keep-alive
Last-Modified: Mon, 17 Oct 2016 03:54:20 GMT
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Android/iOS的WebView控件都默认支持跨域访问。
以下是Android WebView配置跨域访问的方法, 默认是true,即允许跨域访问。
/**
* Sets whether JavaScript running in the context of a file scheme URL
* should be allowed to access content from other file scheme URLs. To
* enable the most restrictive, and therefore secure policy, this setting
* should be disabled. Note that the value of this setting is ignored if
* the value of {@link #getAllowUniversalAccessFromFileURLs} is true.
* Note too, that this setting affects only JavaScript access to file scheme
* resources. Other access to such resources, for example, from image HTML
* elements, is unaffected. To prevent possible violation of same domain policy
* on {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} and earlier
* devices, you should explicitly set this value to {@code false}.
* <p>
* The default value is true for API level
* {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
* and false for API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
* and above.
*
* @param flag whether JavaScript running in the context of a file scheme
* URL should be allowed to access content from other file
* scheme URLs
*/
public abstract void setAllowFileAccessFromFileURLs(boolean flag);
解决跨域问题其实就是要配置tomcat,让http响应头添加Access-Control-Allow-Origin:*
原理类似于OkHttp的拦截器interceptor, 在每个响应头添加Access-Control-Allow-Origin:*
package com.example.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CORSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
然后在web.xml配置拦截器Filter即可。
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>com.example.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>