JsonRpc源码--处理http请求源码刨析
从jsonRpc接入http请求直至开始业务逻辑处理总体层级如下:
JsonServiceExporter->handleRequest-> handle -> handleRequest0 ->handleRequest -> handleJsonNodeRequest -> handleObject -> methodInvoke
- google的jsonrpc4j通过实现springframework中的httpRequestHandler来对请求进行处理;源码如下:
package com.googlecode.jsonrpc4j.spring;import com.googlecode.jsonrpc4j.JsonRpcServer;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.HttpRequestHandler;class JsonServiceExporter extends AbstractJsonServiceExporter implements HttpRequestHandler {private JsonRpcServer jsonRpcServer;JsonServiceExporter() {}protected void exportService() {this.jsonRpcServer = this.getJsonRpcServer();}public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.jsonRpcServer.handle(request, response);response.getOutputStream().flush();}
}
- 进入handle可以看到在此层会对捕获http请求中出现的所有异常,并进行异常处理,回显jsonrpc中自定义的错误代码以及结构;源码如下:
/*** Handles a servlet request.** @param request the {@link HttpServletRequest}* @param response the {@link HttpServletResponse}* @throws IOException on error*/
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {logger.debug("Handling HttpServletRequest {}", request);response.setContentType(contentType);OutputStream output = response.getOutputStream();InputStream input = getRequestStream(request);int result = ErrorResolver.JsonError.PARSE_ERROR.code;int contentLength = 0;ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();try {String acceptEncoding = request.getHeader(ACCEPT_ENCODING);result = handleRequest0(input, output, acceptEncoding, response, byteOutput);contentLength = byteOutput.size();} catch (Throwable t) {if (StreamEndedException.class.isInstance(t)) {logger.debug("Bad request: empty contents!");} else {logger.error(t.getMessage(), t);}}int httpStatusCode = httpStatusCodeProvider == null ? DefaultHttpStatusCodeProvider.INSTANCE.getHttpStatusCode(result): httpStatusCodeProvider.getHttpStatusCode(result);response.setStatus(httpStatusCode);response.setContentLength(contentLength);byteOutput.writeTo(output);output.flush();
}
- 进入handleRequest0 ->handleRequest -> handleJsonNodeRequest,这一步从输入流中读取对应的请求并归属为jsonrpc请求、处理对应请求,并返回结果代码;源码如下:
/*** Handles a single request from the given {@link InputStream},* that is to say that a single {@link JsonNode} is read from* the stream and treated as a JSON-RPC request. All responses* are written to the given {@link OutputStream}.** @param input the {@link InputStream}* @param output the {@link OutputStream}* @return the error code, or {@code 0} if none* @throws IOException on error*/
public int handleRequest(final InputStream input, final OutputStream output) throws IOException {final ReadContext readContext = ReadContext.getReadContext(input, mapper);try {readContext.assertReadable();final JsonNode jsonNode = readContext.nextValue();for (JsonRpcInterceptor interceptor : interceptorList) {interceptor.preHandleJson(jsonNode);}JsonResponse jsonResponse = handleJsonNodeRequest(jsonNode);writeAndFlushValue(output, jsonResponse.getResponse());if (jsonResponse.getExceptionToRethrow() != null) {throw jsonResponse.getExceptionToRethrow();}return jsonResponse.getCode();} catch (JsonParseException | JsonMappingException e) {JsonResponse responseError = createResponseError(VERSION, NULL, JsonError.PARSE_ERROR);writeAndFlushValue(output, responseError.getResponse());return responseError.getCode();}
}
- 进入handleJsonNodeRequest,这里会对请求体中的json对象进行判别并进行对应处理;源码如下:
/*** Handles the given {@link JsonNode} and creates {@link JsonResponse}** @param node the {@link JsonNode}* @return the {@link JsonResponse} instance*/
protected JsonResponse handleJsonNodeRequest(final JsonNode node)throws JsonParseException, JsonMappingException {if (node.isArray()) {return handleArray((ArrayNode) node);}if (node.isObject()) {return handleObject((ObjectNode) node);}return createResponseError(VERSION, NULL, JsonError.INVALID_REQUEST);
}
REQUEST);}
- 这里以handleObject为例,进来后其实就是对json的结构进行验证并调用对应方法;部分解析我会写道下面源码里边;
/*** Handles the given {@link ObjectNode} and creates {@link JsonResponse}** @param node the {@link JsonNode}* @return the {@link JsonResponse} instance*/private JsonResponse handleObject(final ObjectNode node)throws JsonParseException, JsonMappingException {logger.debug("Request: {}", node);// 验证请求中是否存在"jsonRpc" 以及 "method"if (!isValidRequest(node)) {return createResponseError(VERSION, NULL, JsonError.INVALID_REQUEST);}// 获取对应请求idObject id = parseId(node.get(ID));// 验证参数是否为空String jsonRpc = hasNonNullData(node, JSONRPC) ? node.get(JSONRPC).asText() : VERSION;if (!hasNonNullData(node, METHOD)) {return createResponseError(jsonRpc, id, JsonError.METHOD_NOT_FOUND);}// 获取方法路径信息final String fullMethodName = node.get(METHOD).asText();final String partialMethodName = getMethodName(fullMethodName);final String serviceName = getServiceName(fullMethodName);Set<Method> methods = findCandidateMethods(getHandlerInterfaces(serviceName), partialMethodName);if (methods.isEmpty()) {return createResponseError(jsonRpc, id, JsonError.METHOD_NOT_FOUND);}// 验证方法参数是否齐全AMethodWithItsArgs methodArgs = findBestMethodByParamsNode(methods, node.get(PARAMS));if (methodArgs == null) {return createResponseError(jsonRpc, id, JsonError.METHOD_PARAMS_INVALID);}try (InvokeListenerHandler handler = new InvokeListenerHandler(methodArgs, invocationListener)) {try {// 若设置预处理拦截器则会在此处拦截请求if (this.requestInterceptor != null) {this.requestInterceptor.interceptRequest(node);}// serviceName 其实就是我们通过@JsonRpcService设置的层级,在程序启动时会自动加载到内存当中Object target = getHandler(serviceName);// interceptors preHandlefor (JsonRpcInterceptor interceptor : interceptorList) {interceptor.preHandle(target, methodArgs.method, methodArgs.arguments);}// invocation 做内部方法调用执行业务逻辑JsonNode result = invoke(target, methodArgs.method, methodArgs.arguments);handler.result = result;// interceptors postHandle 若设置post拦截器则会在此处拦截请求for (JsonRpcInterceptor interceptor : interceptorList) {interceptor.postHandle(target, methodArgs.method, methodArgs.arguments, result);}// 验证id不为空if (!isNotificationRequest(id)) {return createResponseSuccess(jsonRpc, id, handler.result);}return new JsonResponse(null, JsonError.OK.code);} catch (JsonParseException | JsonMappingException e) {throw e; // rethrow this, it will be handled as PARSE_ERROR later} catch (Throwable e) {handler.error = e;return handleError(id, jsonRpc, methodArgs, e);}}}
JsonRpc源码--处理http请求源码刨析相关推荐
- HTTP状态码、接口请求状态码
HTTP状态码是由三位数字组成的数字代码,用于表示HTTP协议处理请求时的返回状态.状态码通常由服务端发送,客户端通过接收状态码来了解请求是否成功,以及出现错误时出错的原因. 以下是HTTP状态码的详 ...
- Tomcat 处理 HTTP 请求源码分析(下)【转】
原文地址:https://www.infoq.cn/article/zh-tomcat-http-request-2 很多开源应用服务器都是集成 tomcat 作为 web container 的,而 ...
- Squid 代理服务器 编译源码 伪造HTTP_X_FORWARDED_FOR 请求头
本实验操作系统选用 CentOS release 5.6 (Final) 实验目的实现 Squid 代理服务器 编译源码 伪造HTTP_X_FORWARDED_FOR 请求头 .使其显示任意IP 过 ...
- Okhttp同步请求源码分析
进阶android,OKhttp源码分析--同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的. 今天我们来分析一下OKhttp ...
- Spring源码解析 -- SpringWeb请求参数获取解析
Spring源码解析 – SpringWeb请求参数获取解析 简介 在文章:Spring Web 请求初探中,我们看到最后方法反射调用的相关代码,本篇文章就探索其中的参数是如何从请求中获取的 概览 方 ...
- Spring源码解析 -- SpringWeb请求映射Map初始化
简介 在上篇文章中,大致解析了Spring如何将请求路径与处理方法进行映射,但映射相关的初始化对于我们来说还是一团迷雾 本篇文章就来探索下,请求路径和处理方法的映射,是如何进行初始化的 概览 基于上篇 ...
- Spring 源码解析 -- SpringWeb请求映射解析
Spring 源码解析 – SpringWeb请求映射解析 简介 基于上篇请求路径初步探索,了解到了一个请求到具体处理方法的大致路径,本篇就继续探索,看下路径是如何匹配到处理方法的 概览 基于上篇:S ...
- RocketMQ源码(十七)—Broker处理DefaultMQPushConsumer发起的拉取消息请求源码
转载来源: RocketMQ源码(19)-Broker处理DefaultMQPushConsumer发起的拉取消息请求源码[一万字]_刘Java的博客-CSDN博客 此前我们学习了RocketMQ源码 ...
- RocketMQ源码(19)—Broker处理DefaultMQPushConsumer发起的拉取消息请求源码【一万字】
基于RocketMQ release-4.9.3,深入的介绍了Broker处理DefaultMQPushConsumer发起的拉取消息请求源码. 此前我们学习了RocketMQ源码(18)-Defau ...
最新文章
- [Vue.js进阶]从源码角度剖析vue-router(三)
- 构设计杂谈004——架构师
- JavaScript快速上手入门
- 【分解质因数】【树状数组】【快速幂】codeforces 2014 ACM-ICPC Vietnam National Second Round E. ACM...
- oracle大批量数据统计,加速Oracle大批量数据处理的2个好用方案
- Redis Cluster搭建方法简介22211111
- 交换机的基本配置实验报告_无线网络设计配置即实验报告
- EPSnbsp;QOS体系图的解读
- postgresql开启历史查询记录日志
- ubnt路由器虚拟服务器,UBNT UAP系列 Wi-Fi设置教程 装修必看
- Android手机HC-05蓝牙连接Arduino nano获取DHT-11温湿度传感器数据
- uniapp获取云服务空间 数据
- 10 个Web3 设计灵感网站
- SIPWeb视频对讲,群呼,广播会议一体方案分析
- 曹雪芹诗歌中的鸿蒙,曹雪芹的诗词丢失,红楼梦里的诗句
- 进程和线程的区别,进程间通信方式,怎么选择比较好
- 在互联网上班是什么感觉?
- 不懂SEO该如何做搜索引擎优化?
- 复杂网络分析工具总结
- 1.3编程实现从键盘依次输入姓名(字符串)、年龄(整型)、性别(字符)和成绩(浮点型),然后依次显示上述内容