从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请求源码刨析相关推荐

  1. HTTP状态码、接口请求状态码

    HTTP状态码是由三位数字组成的数字代码,用于表示HTTP协议处理请求时的返回状态.状态码通常由服务端发送,客户端通过接收状态码来了解请求是否成功,以及出现错误时出错的原因. 以下是HTTP状态码的详 ...

  2. Tomcat 处理 HTTP 请求源码分析(下)【转】

    原文地址:https://www.infoq.cn/article/zh-tomcat-http-request-2 很多开源应用服务器都是集成 tomcat 作为 web container 的,而 ...

  3. Squid 代理服务器 编译源码 伪造HTTP_X_FORWARDED_FOR 请求头

    本实验操作系统选用 CentOS release 5.6 (Final) 实验目的实现 Squid 代理服务器 编译源码 伪造HTTP_X_FORWARDED_FOR  请求头 .使其显示任意IP 过 ...

  4. Okhttp同步请求源码分析

    进阶android,OKhttp源码分析--同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的. 今天我们来分析一下OKhttp ...

  5. Spring源码解析 -- SpringWeb请求参数获取解析

    Spring源码解析 – SpringWeb请求参数获取解析 简介 在文章:Spring Web 请求初探中,我们看到最后方法反射调用的相关代码,本篇文章就探索其中的参数是如何从请求中获取的 概览 方 ...

  6. Spring源码解析 -- SpringWeb请求映射Map初始化

    简介 在上篇文章中,大致解析了Spring如何将请求路径与处理方法进行映射,但映射相关的初始化对于我们来说还是一团迷雾 本篇文章就来探索下,请求路径和处理方法的映射,是如何进行初始化的 概览 基于上篇 ...

  7. Spring 源码解析 -- SpringWeb请求映射解析

    Spring 源码解析 – SpringWeb请求映射解析 简介 基于上篇请求路径初步探索,了解到了一个请求到具体处理方法的大致路径,本篇就继续探索,看下路径是如何匹配到处理方法的 概览 基于上篇:S ...

  8. RocketMQ源码(十七)—Broker处理DefaultMQPushConsumer发起的拉取消息请求源码

    转载来源: RocketMQ源码(19)-Broker处理DefaultMQPushConsumer发起的拉取消息请求源码[一万字]_刘Java的博客-CSDN博客 此前我们学习了RocketMQ源码 ...

  9. RocketMQ源码(19)—Broker处理DefaultMQPushConsumer发起的拉取消息请求源码【一万字】

    基于RocketMQ release-4.9.3,深入的介绍了Broker处理DefaultMQPushConsumer发起的拉取消息请求源码. 此前我们学习了RocketMQ源码(18)-Defau ...

最新文章

  1. 干货 | 算法工程师入门第二期——穆黎森讲增强学习(一) 本文作者:大牛讲堂 编辑:刘芳平 2017-07-19 11:38 导语:地平线大牛讲堂算法工程师入门第二期来啦!本期地平线资深算法工程师、增
  2. 阿里云联合中国信通院发布《云计算开放应用架构》标准
  3. 计组第三章系统总线自我总结
  4. python import random 报错_Python import random报错处理办法
  5. Java web小项目_个人主页(1)—— 云环境搭建与项目部署
  6. 深度学习Pytorch--梯度与反向传播笔记
  7. 贪婪算法在求解最小生成树中的应用(JAVA)--Kruskal算法
  8. php框架中数据库模型层原理,简单模拟ThinkPHP框架模型层对数据库的链式操作-Go语言中文社区...
  9. python中多条件语句_Python中的带条件语句
  10. [转] 谈谈MIXI的开源SNS架构
  11. 直播app源码用php做直播平台开发怎么样?
  12. arccatalog点要素显示不完_2020年仅剩100天,你的年假休完了吗?关于年假你不知道的7点!...
  13. oracle11g本地安装,windows64位机oracle11g+pl/sql安装教程图解
  14. wifi连接上不能上网怎么办服务器无响应,​wifi连接上不能上网是怎么回事,看完你就恍然大悟了...
  15. TypesScript + Nodejs + Express + Mongoose 实现 RESTful API 实战视频教程(33 个视频)
  16. 总结——》【养生之道】
  17. In me the tiger sniffs the rose.
  18. 系统错误null是什么意思_为什么NULL是错误的?
  19. Docker安装Tomcat镜像并部署web项目简述
  20. 产品经理入门:一、产品、产品经理

热门文章

  1. C语言 用自己的代码实现sqrt和pow函数(实现开方和求幂)
  2. adb驱动安装和使用报错笔记
  3. php api获取二维码、组合生成图片
  4. IDEA安装插件(activate-power-mode )之后总是出现绿色的max字样,怎么去掉呢?
  5. 刑事案件中哪些属于自诉案件?
  6. linux内核编程_内核线程kthread_run
  7. linux中的软件管理(包括配置本地yum源、配置共享yum源、第三方仓库的搭建、yum命令、rpm命令)
  8. MyBatis08:ResultMap 的结果集映射
  9. 新增书籍类别下拉框加载、书籍上下架功能
  10. Linux下清除缓存 drop_caches, sysctl