[JAVA] Implementieren wir eine Funktion, um die Anzahl der Zugriffe auf die API mit SpringBoot + Redis zu begrenzen

Einführung

Im Moment denke ich, dass es viele Fälle gibt, in denen die API-Schnittstelle verwendet wird. Wenn Sie die API jedoch zu oft aufrufen, kann sich die serverseitige Verarbeitung verzögern. Es bedeutet, dass etwas Schlimmes passieren wird. Dieses Mal habe ich diesen Artikel nach sorgfältiger Prüfung und Überlegung geschrieben, um die Anzahl der Zugriffe auf die API zu begrenzen.

Umgebung

Sie müssen sowohl Spring Boot- als auch Redis-Kenntnisse haben.

Methode

Als Implementierungsrichtlinie wird sie in Form von Anmerkungen hauptsächlich mithilfe von Spring Boot und Redis implementiert. Sie können die Details sehen, indem Sie sich den Kommentar ansehen.

1. Erstellen Sie eine Anmerkungsklasse

AccessLimit.java


import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * @author Hyman
 * @date 2019/12/25 11:12
 */
@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {

    //Zeitlimit(Sekunden)
    int seconds();
    //Maximale Anzahl von Zugriffen
    int maxCount();
    //Anmeldestatus
    boolean needLogin() default true;
}

2. Erstellen Sie eine Interceptor-Klasse

ApiLimitInterceptor.java


import com.alibaba.fastjson.JSON;
import com.example.demo.action.AccessLimit;
import com.example.demo.redis.RedisService;
import com.example.demo.result.CodeMsg;
import com.example.demo.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;

/**
 * @author Hyman
 * @date 2019/12/25 11:22
 */
@Component
public class ApiLimitInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private RedisService redisService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //Finden Sie heraus, ob es sich bei der Anforderung um eine HandlerMethod handelt
        if(handler instanceof HandlerMethod){

            HandlerMethod hm = (HandlerMethod) handler;

            //Rufen Sie die Annotation über der Methode ab und prüfen Sie, ob eine AccessLimit-Annotation vorhanden ist
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if(accessLimit == null){
         //Machen Sie nichts ohne die AccessLimit-Annotation
                return true;
            }
       
            //Holen Sie sich das Zeitlimit
            int seconds = accessLimit.seconds();
            //Holen Sie sich die maximale Anzahl von Zugriffen
            int maxCount = accessLimit.maxCount();
            boolean login = accessLimit.needLogin();
            String key = request.getRequestURI();

            //Wenn eine Anmeldung erforderlich ist, gehen Sie wie folgt vor:
            if(login){
                //Ich werde den Authentifizierungsteil hier weglassen
                // key+=""+"userInfo";
            }

            //Holen Sie sich die Anzahl der Zugriffe von redis
            AccessKey ak = AccessKey.withExpire(seconds);
            Integer count = redisService.get(ak,key,Integer.class);

       //Erstellen Sie eine Verzweigung und führen Sie jeden Prozess aus
            if(count == null){
                //Beim ersten Zugriff
                redisService.set(ak,key,1);
            }else if(count < maxCount){
                //Zugriffsanzahl + 1
                redisService.incr(ak,key);
            }else{
                //Wenn die maximale Anzahl von Zugriffen überschritten wird, wird eine Fehlermeldung erstellt und zurückgegeben.
                render(response,"Die maximale Anzahl von Zugriffen wird innerhalb der angegebenen Zeit überschritten."); //
                return false;
            }
        }

        return true;

    }
    
 /**
  *Wenn die maximale Anzahl von Zugriffen überschritten wird, wird eine Fehlermeldung erstellt und zurückgegeben.
  */
  private void render(HttpServletResponse response, CodeMsg cm)throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str  = JSON.toJSONString(Result.error(cm));
        out.write(str.getBytes("UTF-8"));
        out.flush();
        out.close();
    }
}

3. Platzieren Sie die Interceptor-Klasse

Registrieren Sie die in 2 oben erstellte Interceptor-Klasse in Spring Boot.

WebConfig.java


import com.example.demo.ExceptionHander.ApiLimitInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * @author Hyman
 * @date 2019/11/31 15:58
 */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private ApiLimitInterceptor interceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor);
    }
}

4. Erstellen Sie einen Controller

Ich habe einen Controller erstellt und @AccessLimit über die Methode gesetzt. Sobald dies erledigt ist, testen wir mit Postman.

ApiLimitController.java


import com.example.demo.result.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author Hyman
 * @date 2019/12/25 13:21
 */
@Controller
public class ApiLimitController {

    //Zeit: 5 Sekunden,Maximale Anzahl von Zugriffen:5 ,Anmeldestatus: Erforderlich
    @AccessLimit(seconds=5, maxCount=5, needLogin=true)
    @RequestMapping("/ApiLimitTest")
    @ResponseBody
    public Result<String> ApiLimitTest(){
        return Result.success("Erfolgreiche Anfrage!");
    }
 }

Schließlich

Vielen Dank für das Lesen bis zum Ende. Bitte zögern Sie nicht, auf Teile hinzuweisen, die Sie für seltsam halten. Vielen Dank.

Recommended Posts

Implementieren wir eine Funktion, um die Anzahl der Zugriffe auf die API mit SpringBoot + Redis zu begrenzen
Versuchen Sie, eine Anmeldefunktion mit Spring-Boot zu implementieren
So greifen Sie mit der TCP-Funktion von Spring Integration direkt auf Socket zu
Ich habe versucht, mit HCE-F von Android eine Funktion zu implementieren, die Felica Lite entspricht
Schreiben wir eine Lambda-Funktion, die Amazon API Gateway in die Spring Cloud-Funktion integriert.
Lassen Sie uns schreiben, wie API mit SpringBoot + Docker von 0 erstellt wird
Finden Sie mit Kotlin die Anzahl der Tage in einem Monat
Versuchen Sie, die Idee eines zweidimensionalen Arrays mit einem eindimensionalen Array nachzuahmen
Ich habe versucht, die Ergebnisse vor und nach der Date-Klasse mit einer geraden Zahl auszudrücken
Ich habe versucht, die Bildvorschau mit Rails / jQuery zu implementieren
Eine Geschichte über das Erreichen der League Of Legends-API mit JAVA
[Illustration] Finden der Summe von Münzen mit einer rekursiven Funktion [Ruby]
Eine Geschichte, die ich mit der Stream-API von Java8 einem Prozess schreiben wollte, der einer while-Anweisung entspricht
Die Geschichte eines Game Launcher mit automatischer Ladefunktion [Java]
Lassen Sie uns das Ergebnis der Analyse von Java-Bytecode in einem Klassendiagramm ausdrücken
So konvertieren Sie ein Array von Strings mit der Stream-API in ein Array von Objekten
[Rails] Implementieren Sie die Produktkauffunktion mit einer bei PAY.JP registrierten Kreditkarte
Ich habe versucht, den Zugriff von Lambda → Athena mit AWS X-Ray zu visualisieren
So implementieren Sie die E-Mail-Authentifizierungsfunktion zum Zeitpunkt der Benutzerregistrierung
So bestimmen Sie die Anzahl der Parallelen
So implementieren Sie TextInputLayout mit Validierungsfunktion
So erhalten Sie die ID eines Benutzers, der sich in Swift bei Firebase authentifiziert hat
Der Name ist und das Alter ist Senden Sie eine Benachrichtigung an Slack mit der Java-freien Version von Sentry (mit Lambda)
Machen Sie einen Rand links vom TextField
Überschreiben Sie den Inhalt der Konfiguration mit Spring-boot + JUnit5
So implementieren Sie die Brotkrumenfunktion mit gretel
[Android] Implementieren Sie schnell die Funktion zum Anzeigen des Passworts
Versuchen Sie, die Anmeldefunktion mit Spring Boot zu implementieren
[Für Anfänger] So implementieren Sie die Löschfunktion
Lassen Sie uns eine Suchfunktion mit Rails (Ransack) machen
So erstellen Sie einen Jenkins-Server mit einem Docker-Container unter CentOS 7 von VirtualBox und greifen von einem lokalen PC auf den Jenkins-Server zu
Erste Schritte mit Doma-Einführung in die Kriterien-API
Ich habe versucht, ein Tool zum Vergleichen von Amazon-Produktpreisen auf der ganzen Welt mit Java, der Amazon Product Advertising API und der Currency API (29.01.2017) zu erstellen.
Ich habe die Anzahl der Taxis mit Ruby überprüft
Ich habe versucht, den Betrieb der http-Anfrage (Put) mit dem Talented API Tester zu überprüfen
So legen Sie ein Wiederholungslimit für Sidekiq fest und benachrichtigen tote Warteschlangen mit Slack
Ich habe eine Funktion zum Registrieren von Bildern bei der API in Spring Framework erstellt. Teil 1 (API Edition)
3. Erstellen Sie eine Datenbank für den Zugriff über das Webmodul
So führen Sie die SpringBoot-App als Dienst aus
Greifen Sie mit jdbcTemplate auf das integrierte h2db des Spring Boot zu
Die Geschichte, einen Reverse-Proxy mit ProxyServlet zu erstellen
Implementieren Sie iOS14 UICollectionView mit dem minimal erforderlichen Code.
Begrenzen Sie die Anzahl der Threads mithilfe des Java Executor Service
Warum mit Singleton anstelle einer statischen Methode implementieren?
Ich möchte der Kommentarfunktion eine Löschfunktion hinzufügen
Die Geschichte, wie ein Docker-Container mit GitHub-Aktionen in die GitHub-Paketregistrierung und den Docker-Hub verschoben wird
So verwalten Sie den Unterschied in jeder Umgebung mit yml, ohne die Anzahl von RAILS_ENV zu erhöhen
Implementierung einer starken API für "Ich möchte ~~ auf dem Bildschirm anzeigen" mit einfachem CQRS
Lassen Sie uns herausfinden, wie Sie mit Request Body mit der REST-API von Spring Boot empfangen können
Eine Geschichte über einen Studenten, der aufgrund der SARS-CoV-2-Epidemie verschont blieb und schließlich eine Twitter-App erstellte und schließlich an die Grenzen der Twitter-API stieß.