NutzCN Logo
问答 用nginx转发websocket请求时,有的请求报404 问题
发布于 11天前 作者 qq_42f4c888 118 次浏览 复制 上一个帖子 下一个帖子
标签: nginx

用nginx转发websocket请求时,有的请求报404 问题,但大部分websocket请求没有问题。现在http请求和websocket请求使用的是同一个服,同一个端口。
nginx 的access log 404问题如下
172.31.30.154 - - [07/Aug/2018:20:20:11 +0000] "GET /websocket/932615295046688 HTTP/1.1" 域名地址 404 781 68
但大部分的access log 为101
172.31.30.154 - - [07/Aug/2018:20:20:18 +0000] "GET /websocket/934446773453856 HTTP/1.1" 域名地址 101 737 4616
nginx 配置如下

server{
    listen     80;
    server_name     域名地址;
    charset  utf-8;
    access_log       logs/access.log main;
    error_log         logs/error.log;
    client_max_body_size      30m;
    location / {
        proxy_pass http://127.0.0.1:8082;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
10 回复

如果不能重现,那就无解

不能重现出来

debug undertow 源码,看到请求已经到undertow了执行到undertow 的 PathHandler 的 handleRequest 并打印出日志
Matched default handler path /websocket/93602931123
正常应该会继续走到JsrWebSocketFilter的doFilter 中的,但不知道为什么没有走到就返回404了
了解什么原因吗?

是不是爬虫的请求, 非客户端的请求?

/websocket/{param} 这个param是uid,数据库中是有这个uid的信息的。而且看到有多次请求都没有成功

这样才是正确写法,不过不影响的样子

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;

最好还是想办法重现

通过加日志,发现websocket握手时 JsrWebSocketFilter.java 的 doFilter 中 从request中获取Upgrade 字段时为空。也就是说从客户端发起websocket握手时传的 Upgrade 为空?@wendal 有遇到过握手时 Upgarde 为空的情况吗?

 @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        if (req.getHeader(Headers.UPGRADE_STRING) != null) {
            final ServletWebSocketHttpExchange facade = new ServletWebSocketHttpExchange(req, resp, peerConnections);

            String path;
            if (req.getPathInfo() == null) {
                path = req.getServletPath();
            } else {
                path = req.getServletPath() + req.getPathInfo();
            }
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            UndertowLogger.REQUEST_LOGGER.debugf("path %s", path);
            PathTemplateMatcher.PathMatchResult<WebSocketHandshakeHolder> matchResult = pathTemplateMatcher.match(path);
            if (matchResult != null) {
                Handshake handshaker = null;
                for (Handshake method : matchResult.getValue().handshakes) {
                    if (method.matches(facade)) {
                        handshaker = method;
                        break;
                    }
                }

                if (handshaker != null) {
                    if(container.isClosed()) {
                        resp.sendError(StatusCodes.SERVICE_UNAVAILABLE);
                        return;
                    }
                    facade.putAttachment(HandshakeUtil.PATH_PARAMS, matchResult.getParameters());
                    facade.putAttachment(HandshakeUtil.PRINCIPAL, req.getUserPrincipal());
                    final Handshake selected = handshaker;
                    final HttpSessionImpl session = (HttpSessionImpl) req.getSession(false);
                    facade.upgradeChannel(new HttpUpgradeListener() {
                        @Override
                        public void handleUpgrade(StreamConnection streamConnection, HttpServerExchange exchange) {

                            WebSocketChannel channel = selected.createChannel(facade, streamConnection, facade.getBufferPool());
                            peerConnections.add(channel);
                            if(session != null) {
                                final Session underlying;
                                if (System.getSecurityManager() == null) {
                                    underlying = session.getSession();
                                } else {
                                    underlying = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(session));
                                }
                                List<WebSocketChannel> connections;
                                synchronized (underlying) {
                                    connections = (List<WebSocketChannel>) underlying.getAttribute(SESSION_ATTRIBUTE);
                                    if(connections == null) {
                                        underlying.setAttribute(SESSION_ATTRIBUTE, connections = new ArrayList<>());
                                    }
                                    connections.add(channel);
                                }
                                final List<WebSocketChannel> finalConnections = connections;
                                channel.addCloseTask(new ChannelListener<WebSocketChannel>() {
                                    @Override
                                    public void handleEvent(WebSocketChannel channel) {
                                        synchronized (underlying) {
                                            finalConnections.remove(channel);
                                        }
                                    }
                                });
                            }
                            callback.onConnect(facade, channel);
                        }
                    });
                    handshaker.handshake(facade);
                    return;
                }
            }
        }
        chain.doFilter(request, response);
    }

那就是客户端的问题了

继续再调查调查,可能跟不同版本的浏览器有关系。客户端直接调用的是手机浏览器发送的。

添加回复
请先登陆
回到顶部