Flash实现Websocket的跨域问题-安全沙箱问题解决办法

笔者在开发一款大型的直播交互平台时采用了Websocket技术来实现文字、弹幕与语音的交互,当前主流的浏览器都内建了Websocket的支持,因此直播平台在大多数浏览器上运行良好。但由于平台需要支持IE8(或以下版本)浏览器,由于IE没有内置的Websocket支持,因此考虑采用Flash实现一个代理层来支持Websocket,当Flash代码实现好后在IE中一运行,发现总是提示安全沙箱冲突,如下所示:

 


[WebSocket] cannot connect to Web Socket server at ws://192.168.1.202:9168/ (SecurityError: Error #2048: 安全沙箱冲突:http://192.168.1.202:8080/js/swf/WebSocketInsecure.swf 不能从 192.168.1.202:9168 加载数据。)
make sure the server is running and Flash socket policy file is correctly placed
 

 

通过分析原因后发现是Flash的安全策略导致的问题,flash发起socket通讯时,如果swf文件与通讯的服务器地址不一致:包括IP地址(域)与端口,就会向通讯所在的服务器请求安全策略文件,例如:如果Flash所在的页面地址为 http://192.168.100:8080/index.html,而Websocket需要访问 192.168.100:8168这个地址,虽然访问的服务器的IP地址相同,但由于端口不一样,一个为8080,另一个为8168,Flash也会把它们当做不同的域,需要安全策略文件。

 

Flash请求安全策略文件的步骤如下:

1)Flash首先使用 默认TCP端口 843 向服务器发送XML字符串 "<policy-file-request/>\0"(共23个字节)来请求安全策略文件,注意这个字符串是通过xmlsocket协议发送的,xmlsocket协议需要在通讯的数据末尾追加一个null结尾字符'\0'(ASCII值为0,类似于C语言的null结尾字符串),因此总共发送23个字符到服务器请求安全策略文件。

2)Flash首先使用 默认843端口来获取安全策略文件,如果连接不成功,然后再用当前请求的地址向服务器发送安全策略文件请求,例如,如果向地址 192.168.100:843发起连接无效,则会继续向192.168.100:8080这个地址发送xmlsocket请求;

3)服务器端接收到TCP数据后,一定要先判断是否是Flash的安全策略请求,如果服务器收到了"<policy-file-request/>\0"这个字符串,则应该向客户端(指Flash播放器)返回安全策略文件,一个安全策略文件的示例内容如下:

 


<?xml version = "1.0" encoding = "utf-8"?>
<cross-domain-policy> 
<allow-access-from domain="*" to-ports="8168" /> 
<allow-access-from domain="*.iavcast.com" to-ports="10086,20086" />
<allow-access-from domain="*.huayisoft.net" to-ports="*" />
</cross-domain-policy>

一般只需要对以上文件的xml节点allow-access-from进行修改即可。

策略文件是用于告诉flash客户端, 允许哪些域的主机通过哪些端口进行连接。

 

注意发送时,策略文件的内容应该包含末尾的结尾 \0 字符,这是Flash的xmlsocket的要求。

 

 

 

 

 

WebSocket跨域问题可以通过在服务端进行配置来解决。具体方法如下: 1.在服务端配置允许跨域访问的信息,例如在Spring Boot中可以使用@CrossOrigin注解或者配置CorsFilter来实现。 2.在客户端建立WebSocket连接时,需要在请求头中添加Origin字段,指定允许跨域的源地址。 3.在服务端接收到WebSocket连接请求时,需要在响应头中添加Access-Control-Allow-Origin字段,指定允许跨域的源地址。 下面是一个使用Spring Boot解决WebSocket跨域问题的例子: ```java // 1.在WebSocket配置类中添加@CrossOrigin注解 @Configuration @EnableWebSocket @CrossOrigin(origins = "http://localhost:8080") public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("*"); } @Bean public WebSocketHandler myHandler() { return new MyHandler(); } } // 2.在客户端建立WebSocket连接时添加Origin字段 var socket = new WebSocket("ws://localhost:8080/myHandler"); socket.onopen = function(event) { socket.send("Hello, Server!"); }; // 3.在服务端响应头中添加Access-Control-Allow-Origin字段 public class MyHandler implements WebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { session.sendMessage(new TextMessage("Hello, Client!")); session.getAttributes().put("username", "guest"); session.getAttributes().put("uid", "123456"); session.getAttributes().put("timestamp", System.currentTimeMillis()); session.getAttributes().put("ip", session.getRemoteAddress().getHostName()); session.getAttributes().put("port", session.getRemoteAddress().getPort()); session.getAttributes().put("protocol", session.getHandshakeHeaders().get("Sec-WebSocket-Protocol").get(0)); session.getAttributes().put("origin", session.getHandshakeHeaders().get("Origin").get(0)); session.getAttributes().put("user-agent", session.getHandshakeHeaders().get("User-Agent").get(0)); session.getAttributes().put("referer", session.getHandshakeHeaders().get("Referer").get(0)); session.getAttributes().put("cookie", session.getHandshakeHeaders().get("Cookie").get(0)); session.getAttributes().put("path", session.getUri().getPath()); session.getAttributes().put("query", session.getUri().getQuery()); session.getAttributes().put("params", session.getUri().getQueryParams()); session.getAttributes().put("headers", session.getHandshakeHeaders()); session.getAttributes().put("attributes", session.getAttributes()); session.getAttributes().put("principal", session.getPrincipal()); session.getAttributes().put("remote-address", session.getRemoteAddress()); session.getAttributes().put("local-address", session.getLocalAddress()); session.getAttributes().put("binary-message-size-limit", session.getBinaryMessageSizeLimit()); session.getAttributes().put("text-message-size-limit", session.getTextMessageSizeLimit()); session.getAttributes().put("idle-timeout", session.getIdleTimeout()); session.getAttributes().put("uri-variables", session.getUriVariables()); session.getAttributes().put("handshake-timeout", session.getHandshakeTimeout()); session.getAttributes().put("heartbeat-interval", session.getHeartbeatInterval()); session.getAttributes().put("send-timeout", session.getSendTimeout()); session.getAttributes().put("message-size-limit", session.getMessageSizeLimit()); session.getAttributes().put("extensions", session.getExtensions()); session.getAttributes().put("subprotocols", session.getAcceptedProtocol()); session.getAttributes().put("ssl-session", session.getSslSession()); session.getAttributes().put("local-name", session.getLocalAddress().getHostName()); session.getAttributes().put("local-port", session.getLocalAddress().getPort()); session.getAttributes().put("remote-name", session.getRemoteAddress().getHostName()); session.getAttributes().put("remote-port", session.getRemoteAddress().getPort()); session.getAttributes().put("remote-user", session.getPrincipal().getName()); session.getAttributes().put("remote-ip", session.getRemoteAddress().getAddress().getHostAddress()); session.getAttributes().put("remote-host", session.getRemoteAddress().getHostName()); session.getAttributes().put("remote-uri", session.getUri().toString()); session.getAttributes().put("remote-headers", session.getHandshakeHeaders()); session.getAttributes().put("remote-attributes", session.getAttributes()); session.getAttributes().put("remote-protocol", session.getHandshakeHeaders().get("Sec-WebSocket-Protocol").get(0)); session.getAttributes().put("remote-origin", session.getHandshakeHeaders().get("Origin").get(0)); session.getAttributes().put("remote-user-agent", session.getHandshakeHeaders().get("User-Agent").get(0)); session.getAttributes().put("remote-referer", session.getHandshakeHeaders().get("Referer").get(0)); session.getAttributes().put("remote-cookie", session.getHandshakeHeaders().get("Cookie").get(0)); session.getAttributes().put("remote-path", session.getUri().getPath()); session.getAttributes().put("remote-query", session.getUri().getQuery()); session.getAttributes().put("remote-params", session.getUri().getQueryParams()); session.getAttributes().put("remote-extensions", session.getExtensions()); session.getAttributes().put("remote-subprotocols", session.getAcceptedProtocol()); session.getAttributes().put("remote-ssl-session", session.getSslSession()); session.getAttributes().put("remote-local-name", session.getLocalAddress().getHostName()); session.getAttributes().put("remote-local-port", session.getLocalAddress().getPort()); session.getAttributes().put("remote-remote-name", session.getRemoteAddress().getHostName()); session.getAttributes().put("remote-remote-port", session.getRemoteAddress().getPort()); session.getAttributes().put("remote-remote-user", session.getPrincipal().getName()); session.getAttributes().put("remote-remote-ip", session.getRemoteAddress().getAddress().getHostAddress()); session.getAttributes().put("remote-remote-host", session.getRemoteAddress().getHostName()); session.getAttributes().put("remote-remote-uri", session.getUri().toString()); session.getAttributes().put("remote-remote-headers", session.getHandshakeHeaders()); session.getAttributes().put("remote-remote-attributes", session.getAttributes()); session.sendMessage(new TextMessage("Hello, Client!")); } @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { session.sendMessage(new TextMessage("Hello, Client!")); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { session.sendMessage(new TextMessage("Hello, Client!")); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { session.sendMessage(new TextMessage("Hello, Client!")); } @Override public boolean supportsPartialMessages() { return false; } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值