GithubHelp home page GithubHelp logo

gugemichael / nesty Goto Github PK

View Code? Open in Web Editor NEW
51.0 13.0 34.0 180 KB

Http RESTful api implemention on Netty async io. More informations at :

Home Page: http://gugemichael.github.io/nesty/

License: Apache License 2.0

Java 95.44% Shell 4.56%

nesty's Introduction

Nesty

Http Restful API framework implemention with Netty

Homepage please visit http://gugemichael.github.io/nesty/

Lastest version

stable with master branch or v0.0.3 branch

develop with v0.0.4 branch

Features

  • HTTP/1.1 and HTTP/1.0 protocol support
  • Http Long-connection supported (also Connection: keep-alive)
  • Internal stats with root url path (analogous to http://ip:port/ directly)

GET, POST, UPDAT, EDELETE

  • Http Restful serialized (usually as json) in string body (With Gson)
  • Http Short Connection on async mode by default (With Netty 4.2)
  • Http request mapping variable support
Annotation From
@Header http header
@RequestParam http url query string or http body key value pairs
@PathVariabl http uri path vairable with {path}
@Body http body
  • Http request mapping method params type support
Class Type Default value (require = false is set) Description
int,short,long 0 primitive
float,double 0.0d primitive
String null string value
Enum null enum class type
Class null from http body serializer parsed

TODO

  • Spring or Mybatis intergrated

  • Http 2.0 support

Usage

  • Simplest http server
public class SimpleHttpServer {

	public static void main(String[] args) throws ControllerRequestMappingException {
		AsyncServerProvider.builder().port(8080).service(NestyProtocol.HTTP)
			.scanHttpController("org.nesty.example.httpserver.handler").start();
	}
}
  • Normal http server
public static void main(String[] args) {

	// 1. build httpserver
	NestyServer server = AsyncServerProvider.builder().port(8080).service(NestyProtocol.HTTP);

	// 2. choose http params. this is unnecessary
	server.option(NestyOptions.IO_THREADS, Runtime.getRuntime().availableProcessors())
		  .option(NestyOptions.WORKER_THREADS, 128)
		  .option(NestyOptions.TCP_BACKLOG, 1024)
		  .option(NestyOptions.TCP_NODELAY, true);

	// 3. scan defined controller class with package name
	server.scanHttpController("com.nesty.test.neptune")
		  .scanHttpController("com.nesty.test.billing")
		  .scanHttpController("org.nesty.example.httpserver.handler");

	// 4. start http server
	if (!server.start())
		System.err.println("NestServer run failed");

	try {
		// join and wait here
		server.join();
		server.shutdown();
	} catch (InterruptedException ignored) {
	}
}
  • Controlloer
@Controller
@RequestMapping("/projects")
public class ServiceController {

	@RequestMapping(value = "/{projectId}", method = RequestMethod.GET)
	public ServiceResponse getProjectById(@PathVariable("projectId") Integer projectId) {
		System.out.println("getProjectById() projectId " + projectId);
		return new ServiceResponse();
	}
}
  • Interceptor
@Interceptor
public class ServiceInterceptor extends HttpInterceptor {

	@Override
	public boolean filter(final HttpContext context) {

		// count the request
		totalRequest.incrementAndGet();

		// show remote address
		if (!context.getRemoteAddress().isEmpty())
			System.out.println(String.format("request from client %s", context.getRemoteAddress()));

		// reject some one which is not we want
		if (context.getRemoteAddress().equals("192.168.1.1"))
			return false;

		// reject request from agent like curl
		if (context.getHttpHeaders().containsKey("User-Agent"))
			return false;

		// OK
		return true;
	}   

	@Override
	public DefaultFullHttpResponse handler(final HttpContext context, DefaultFullHttpResponse response) {

		// compress content if client support
		if ("gzip".equalsIgnoreCase(context.getHttpHeaders().get("Accept-Encoding"))) {
			// compress the body
			ByteBuf compressContent = compressWithGzip(response.content());
			DefaultFullHttpResponse newResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, compressContent);
			response = newResponse;
		}   

		// add more header
		response.headers().add("NestyInceptor", "Nesty is Good");

		return response;
	}   
}
  • More examples

Please visit https://github.com/gugemichael/nesty/wiki/More-Examples

Threads Model

  • Netty Bootstrap(io threads) + ThreadPool(logic threads)

screenshot

Performance

java -server -Xmx4G -Xms4G -Xmn1536M -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DisableExplicitGC

Http short connection

  • Conccurent : 512 http connections
  • Qps : 40,000+
  • Latency : < 10ms

Http long connection (Connection: keep-alive)

  • Conccurent : 4096 http connections
  • Qps : 180,000 ~ 200,000
  • Latency : < 50ms

detail : https://github.com/gugemichael/nesty/wiki/Performance-Detail

nesty's People

Contributors

gugemichael avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nesty's Issues

关于使用GET请求,使用@RequestParam时,标注required为false,前端传递的参数如果是空字符串及:...url...?xxx=&yyy=abc 那么他会报错400 BadRequest。

我只是一个还有一年毕业的实习生,是一个创业公司的开发,我们的服务使用了你的这个web框架,遇到了一个小bug。
bug为:使用GET请求,使用@RequestParam时,标注required为false,前端穿的参数如果是空字符串及:...url...?xxx=&yyy=abc
那么他会报错400 BadRequest。
有两个原因:
1、第一个原因
image
这里如果讲required放前面的话,短路如果required为false就没有任何问题。
2、第二个原因也是核心原因
image
在这只是判断null并没有判断空字符串,所以requured并没有变为false。

这两个都是在org/nesty/core/server/rest/controller/ControllerMethodDescriptor.java当中

你写的这个很厉害,我肯定写不出来,只是提一个小小的建议。

nesty组件中的GenericFileWriter有改进的地方

在多线程环境中,当程序结束时,必须在每个线程中都要进行flush,然后再在某个线程中进行close,才能确保没有数据没被漏掉

这是因为close的时候只会对本线程的thread local buffer进行flush,但是其他线程的thread local buffer中的数据就被漏掉了

可以考虑这样

public static Map<String, ByteArrayBuffer> MAP = new HashMap<>();
/**
 * thread cached calender instances
 */
private ThreadLocal<ByteArrayBuffer> arena = new ThreadLocal<ByteArrayBuffer>() {
    @Override
    protected ByteArrayBuffer initialValue() {
        // Java fill the array buffer with zero
        ByteArrayBuffer result = new ByteArrayBuffer();
        MAP.put(Thread.currentThread().getName(), result);
        return result;
    }
};

@Override
public void close() {
    try {
        if (buffered) {
            for(String key : MAP.keySet()){
                ByteArrayBuffer buffer = MAP.get(key);
                if (buffer.getOffset() != 0)
                    doWrite(buffer.getBuffer(), 0, buffer.getOffset());
                    buffer.clear();
            }
        }
        out.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }


    try {
        out.close();
        out = null;
    } catch (IOException ignored) {
    }
}

请问该框架能否获取请求中的JSON?

示例代码中并没有上述问题的功能,在本地实现之后也报错:
java.lang.RuntimeException: Unable to invoke no-args constructor for interface io.netty.handler.codec.http.FullHttpRequest. Register an InstanceCreator with Gson for this type may fix this problem.
at com.google.gson.internal.ConstructorConstructor$12.construct(ConstructorConstructor.java:210)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:162)
at com.google.gson.Gson.fromJson(Gson.java:803)
at com.google.gson.Gson.fromJson(Gson.java:768)
at com.google.gson.Gson.fromJson(Gson.java:717)
at com.google.gson.Gson.fromJson(Gson.java:689)
at org.nesty.commons.utils.SerializeUtils.decode(SerializeUtils.java:27)
at org.nesty.core.server.rest.controller.ControllerMethodDescriptor.parseParam(ControllerMethodDescriptor.java:168)
at org.nesty.core.server.rest.controller.ControllerMethodDescriptor.resolveParams(ControllerMethodDescriptor.java:156)
at org.nesty.core.server.rest.controller.ControllerMethodDescriptor.invoke(ControllerMethodDescriptor.java:94)
at org.nesty.core.server.rest.controller.URLController.call(URLController.java:56)
at org.nesty.core.server.rest.ExecutorTask.call(ExecutorTask.java:45)
at org.nesty.core.server.rest.ExecutorTask.call(ExecutorTask.java:21)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

比如如下代码:
public ServiceResponse getProjectById(FullHttpRequest request){

ByteBuf jsonBuf = request.content();
String json = jsonBuf.toString(StandardCharsets.UTF_8);
System.out.println("JSON :"+json);

Question about annotation

Hi, I'm interested with this project, and I have a small question.

Since you'll integrate with Spring, why doesn't you use the annotation on spring-context/spring-web directly? As there are @controller already...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.