公司动态
网站通信(一)
浏览器本身也可以看成一个能够联网的客户端程序。当我们在浏览器里访问http://127.0.0.1:8080浏览器会主动和本机的 8080 端口建立连接然后按照 HTTP 协议发送一段数据。所以这次服务端仍然从最熟悉的ServerSocketserverSocketnewServerSocket(8080);SocketsocketserverSocket.accept();等待浏览器访问。浏览器连进来以后通过InputStreaminsocket.getInputStream();就能够读取浏览器发送过来的数据。刚开始把这些内容直接打印出来可以看到类似GET / HTTP/1.1 Host: 127.0.0.1:8080 User-Agent: ... Accept: ... Connection: ...这些内容其实就是 HTTP 请求。前面自己写聊天室时消息格式是自己规定的比如消息类型 消息长度 消息内容现在浏览器和服务器之间同样有协议只不过这套协议已经被规定好了也就是 HTTP。所以从这一点来看HTTP 和前面自己设计的消息协议思路并没有本质区别都是规定“这一段数据中每一部分分别是什么意思”。文章目录一、先写一个简单的登录页面二、点击按钮后怎么把数据发给 Java三、Java 服务端解析 HTTP 请求四、服务器还要按照 HTTP 格式返回结果五、前端接收后端返回的数据一、先写一个简单的登录页面网站前端主要涉及三部分HTML → 页面上有什么 CSS → 页面长什么样 JavaScript → 页面能做什么这次先做一个最简单的登录页面。HTML 主要负责页面结构例如账号inputidusernametypetext/密码inputidpwdtypepassword/inputonclickhello()typebuttonvalue登录/这里用了三个input。第一个用来输入账号。用来输入账号。typetext第二个用来输入密码。typepassword第三个就是登录按钮。typebutton为了后面 JavaScript 能找到账号和密码输入框还给它们分别加了idusername和 id“pwd”页面中还设置了metacharsetutf-8主要是为了正常显示中文。CSS 这部分暂时比较简单.hello{background-color:red;}然后divclasshello就可以把这一块应用对应的样式。二、点击按钮后怎么把数据发给 Java如果页面只有 HTML 和 CSS那么点击按钮以后实际上不会完成登录真正负责交互的是 JavaScript。登录按钮inputonclickhello()typebuttonvalue登录/点击以后会调用hello()这个函数。首先获取用户输入的账号和密码varusernamedocument.getElementById(username).value;varpwddocument.getElementById(pwd).value;这里的document.getElementById()就是根据前面设置的id找到页面中的组件。拿到数据以后这次使用了一个比较原始的网络请求方式varxmlrequestnewXMLHttpRequest();然后打开一个 GET 请求xmlrequest.open(GET,http://127.0.0.1:8080/api/login?usernameusernamepwdpwd,true);假设输入账号admin 密码123456最终浏览器访问的就是http://127.0.0.1:8080/api/login?usernameadminpwd123456/api/login 表示请求哪个功能。? 表示开始携带参数。usernameadmin 表示一个参数。 多个参数之间使用分隔。xmlrequest.send();才真正把请求发送出去。三、Java 服务端解析 HTTP 请求浏览器发出请求以后Java 服务端收到的第一行是GET /api/login?usernameadminpwd123456 HTTP/1.1所以服务端第一步使用BufferedReaderreadernewBufferedReader(newInputStreamReader(in));StringrequestLinereader.readLine();读取 HTTP 请求的第一行,这一行里面已经包含了这次登录需要的大部分信息,先按照空格拆String[]partsrequestLine.split( );可以得到GET /api/login?usernameadminpwd123456 HTTP/1.1其中Stringmethodparts[0];StringfullPathparts[1];就可以分别拿到请求方式和请求地址。接下来再寻找*?*的位置intidxfullPath.indexOf(?);把路径和参数分开,最终得到path /api/login query usernameadminpwd123456然后再按照**拆开参数for(Stringparam:query.split()){每一组再按照拆String[]kvparam.split();最后就能够拿到username admin pwd 123456现在这个版本暂时直接在服务端写死账号密码staticfinalStringVALID_USERadmin;staticfinalStringVALID_PWD123456;然后判断booleansuccessVALID_USER.equals(username)VALID_PWD.equals(password);账号密码为admin / 123456则登录成功其他账号密码则失败。四、服务器还要按照 HTTP 格式返回结果刚开始调试时有一个比较明显的问题虽然服务器已经完成了账号密码判断但是浏览器迟迟拿不到结果。这里和前面写 Socket 聊天不一样聊天室里可以直接os.write(…)发送一句文字。但是浏览器希望收到的是一条符合 HTTP 协议的响应。例如登录成功时现在代码返回HTTP/1.1 200 OK Content-Type: text/html; charsetutf-8 Access-Control-Allow-Origin: * Content-Length: ... 登录成功~代码中实际是StringresponseHTTP/1.1 statusCode statusText\r\nContent-Type: text/html; charsetutf-8\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: body.getBytes().length\r\n\r\n// 空行分隔头部和正文body;这里有一个比较重要的格式响应状态行 响应头 空行 响应正文中间必须有空行把头部和真正返回的数据分开。登录成功时使用200 OK登录失败则使用401 Unauthorized如果路径不存在404 Not Found请求方法不支持405 Method Not Allowed所以浏览器不仅能收到登录成功~还能够知道本次 HTTP 请求到底成功还是失败。五、前端接收后端返回的数据JavaScript 发出请求以后还需要监听服务器什么时候返回页面中使用xmlrequest.onreadystatechangefunction(){if(xmlrequest.readyState4){vardataxmlrequest.responseText;console.log(结果返回data);alert(data);}};其中readyState 4表示这次请求已经完成。然后通过responseText得到 Java 服务端返回的正文。例如服务器返回登录成功~前端最后会通过alert(data);弹窗显示。到这里整个流程就是用户填写账号密码 ↓ 点击登录 ↓ JavaScript获取输入框 ↓ XMLHttpRequest发送GET请求 ↓ Java ServerSocket收到请求 ↓ 解析HTTP请求行 ↓ 取出账号密码 ↓ 执行登录判断 ↓ 返回HTTP响应 ↓ JavaScript读取responseText ↓ 页面显示结果也就是前端 → 网络 → 后端 → 网络 → 前端