WebSocket: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method

使用WebSocket做APP的通知服务,但是批量推送的时候报错:The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method

2021/08/05 09:45:34.364 INFO [task-33261] Base : ===> 收到消息转发给APP(userId=107):{“messageId”:”c73f2e6f-3c36-48a6-91ae-a59854aa992e”}
2021/08/05 09:45:34.365 INFO [task-33261] Base : 发送数据 -> 开始
2021/08/05 09:45:34.389 ERROR [task-33261] o.s.a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected exception occurred invoking async method: public void com.ikonke.ws.system.bus.EventSenderListener.onApplicationEvent(com.ikonke.ws.system.bus.event.EventSender)
java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.checkState(WsRemoteEndpointImplBase.java:1258) ~[tomcat-embed-websocket-9.0.41.jar!/:9.0.41]
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$StateMachine.textStart(WsRemoteEndpointImplBase.java:1220) ~[tomcat-embed-websocket-9.0.41.jar!/:9.0.41]
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendString(WsRemoteEndpointImplBase.java:191) ~[tomcat-embed-websocket-9.0.41.jar!/:9.0.41]
at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendText(WsRemoteEndpointBasic.java:37) ~[tomcat-embed-websocket-9.0.41.jar!/:9.0.41]
at com.ikonke.ws.socket.WSHandler.sendMessage(WSHandler.java:104) ~[classes!/:0.0.1-SNAPSHOT]
at com.ikonke.ws.system.bus.EventSenderListener.onApplicationEvent(EventSenderListener.java:69) ~[classes!/:0.0.1-SNAPSHOT]
at com.ikonke.ws.system.bus.EventSenderListener.onApplicationEvent(EventSenderListener.java:25) ~[classes!/:0.0.1-SNAPSHOT]
at com.ikonke.ws.system.bus.EventSenderListener$$FastClassBySpringCGLIB$$a5414582.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.cloud.sleuth.instrument.async.TraceAsyncAspect.traceBackgroundThread(TraceAsyncAspect.java:70) ~[spring-cloud-sleuth-core-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
at sun.reflect.GeneratedMethodAccessor78.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.2.12.RELEASE.jar!/:5.2.12.RELEASE]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_171]
at org.springframework.cloud.sleuth.instrument.async.TraceRunnable.run(TraceRunnable.java:68) ~[spring-cloud-sleuth-core-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
at org.springframework.cloud.sleuth.instrument.async.TraceRunnable.run(TraceRunnable.java:68) ~[spring-cloud-sleuth-core-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_171]

TEXT_FULL_WRITING的状态是当前会话正在输出数据,那么需要将send的方法改为同步,如下:

public synchronized void sendMessage(Session session, String message) {
    try {
        logger("发送数据 ->  开始");
        session.getBasicRemote().sendText(message);
        logger("发送数据 -> 成功");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

归并排序算法详解

基本思想

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治策略。

将问题分(divide)成一些小的问题然后递归求解

则将分的阶段得到数据进行加工处理,最终形成一个有顺序的序列,这就是分而治之

如下图:1626941416-5987-20161218163120151-452283750

可以看到这种结构很像一棵完全二叉树,归并排序可以使用迭代、递归的方式去实现,这里采用递归;

合并相邻序列

再来看看治阶段,将两个已经有序的子序列合并成一个有序序列,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],实现步骤:

1626941416-4265-20161218194508761-468169540

1626941416-8699-20161218194621308-588010220

代码实现

package com.ikonke.openapi;

import java.util.Arrays;


public class Test2 {
    public static void main(String[] args) {
        int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 排序递归的方法
     *
     * @param arr
     */
    public static void sort(int[] arr) {
        /**
         * 临时数组
         */
        int[] temp = new int[arr.length];
        sort(arr, 0, arr.length - 1, temp);
    }

    /**
     * 分治的方法
     *
     * @param arr
     * @param left
     * @param right
     * @param temp
     */
    private static void sort(int[] arr, int left, int right, int[] temp) {
        if (left < right) {
            //从数组中间开始
            int mid = (left + right) / 2;
            //左边归并排序,使得左子序列有序
            sort(arr, left, mid, temp);

            //右边归并排序,使得右子序列有序
            sort(arr, mid + 1, right, temp);

            //将两个有序子数组合并操作
            merge(arr, left, mid, right, temp);
        }
    }

    /**
     * 数组合并
     *
     * @param arr   原数组
     * @param left
     * @param mid
     * @param right
     * @param temp  临时数组
     */
    private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
        int i = left;//左指针
        int j = mid + 1;//右指针
        int t = 0;//临时数组指针
        while (i <= mid && j <= right) {
            if (arr[i] <= arr[j]) {
                temp[t++] = arr[i++];
            } else {
                temp[t++] = arr[j++];
            }
        }
        while (i <= mid) {//将左边数组赋值到临时数组
            temp[t++] = arr[i++];
        }
        while (j <= right) {//将右边数组赋值到临时数组
            temp[t++] = arr[j++];
        }
        t = 0;
        //数组拷贝替换
        while (left <= right) {
            arr[left++] = temp[t++];
        }
    }
}

执行结果

[1, 2, 3, 4, 5, 6, 7, 8, 9]

总结

归并排序是稳定排序,也是一种十分高效的排序,当进行大数据排序的时候使用归并效率会高很多,如果只有>50个数组,我认为还是使用插入排序、冒泡排序之类的,会合适些。

从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。

堆排序算法详解

概念

堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。

堆是具有以下性质的完全二叉树:

每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;

或每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

如下图:

1626920600-8986-20161217182750011-675658660

同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子

1626920600-3203-20161217182857323-2092264199

该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

接下来,看看堆排序的基本思想及基本步骤:

基本思想

将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列。

步骤

1.构造初始堆

将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。假设给定无序序列结构如下:

1626920600-4223-20161217192038651-934327647

从最后一个非叶子结点开始,叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点,从左至右,从下至上进行调整。

1626920600-2305-20161217192209433-270379236

找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。

1626920600-5824-20161217192854636-1823585260

这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。

1626920600-9719-20161217193347886-1142194411

此时,就将一个无需序列构造成了一个大顶堆。

2.将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。

将堆顶元素9和末尾元素4进行交换

1626920608-5605-20161217194207620-1455153342

重新调整结构,使其继续满足堆定义:

1626920610-9242-20161218153110495-1280388728

再将堆顶元素8与末尾元素5进行交换,得到第二大元素8.

1626920614-9891-20161218152929339-1114983222

后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序

1626920614-5968-20161218152348229-935654830

总结堆排序的基本思路:

  • 将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
  • 将堆顶元素与末尾元素交换,将最大元素”沉”到数组末端;
  • 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

代码

import java.util.Arrays;

public class Test2 {
    public static void main(String[] args) {
        
        int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void sort(int[] arr) {
        //1.构建大顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            //从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(arr, i, arr.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for (int j = arr.length - 1; j > 0; j--) {
            swap(arr, 0, j);//将堆顶元素与末尾元素进行交换
            adjustHeap(arr, 0, j);//重新对堆进行调整
        }

    }

    /**
     * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
     *
     * @param arr
     * @param i
     * @param length
     */
    public static void adjustHeap(int[] arr, int i, int length) {
        int temp = arr[i];//先取出当前元素i
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {//从i结点的左子结点开始,也就是2i+1处开始
            if (k + 1 < length && arr[k] < arr[k + 1]) {//如果左子结点小于右子结点,k指向右子结点
                k++;
            }
            if (arr[k] > temp) {//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                arr[i] = arr[k];
                i = k;
            } else {
                break;
            }
        }
        arr[i] = temp;//将temp值放到最终的位置
    }

    /**
     * 交换元素
     *
     * @param arr
     * @param a
     * @param b
     */
    public static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

最后

堆排序是一种选择排序,整体主要由:构建初始堆 + 交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)…1]逐步递减,近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。

数据结构:图Graph

图的简介

图(Graph)结构是一种非线性的数据结构,图在实际生活中有很多例子,比如交通运输网,地铁网络,社交网络,计算机中的状态执行(自动机)等等都可以抽象成图结构。图结构比树结构复杂的非线性结构。

图结构构成

1.顶点(vertex):图中的数据元素,如图一。

2.边(edge):图中连接这些顶点的线,如图一。

1 

图一

所有的顶点构成一个顶点集合,所有的边构成边的集合,一个完整的图结构就是由顶点集合和边集合组成。图结构在数学上记为以下形式:

G=(V,E)   或者   G=(V(G),E(G))

其中 V(G)表示图结构所有顶点的集合,顶点可以用不同的数字或者字母来表示。E(G)是图结构中所有边的集合,每条边由所连接的两个顶点来表示。

图结构中顶点集合V(G)不能为空,必须包含一个顶点,而图结构边集合可以为空,表示没有边。

图的基本概念

1.无向图(undirected graph)

       如果一个图结构中,所有的边都没有方向性,那么这种图便称为无向图。典型的无向图,如图二所示。由于无向图中的边没有方向性,这样我们在表示边的时候对两个顶点的顺序没有要求。例如顶点VI和顶点V5之间的边,可以表示为(V2, V6),也可以表示为(V6,V2)。

2

图二  无向图

对于图二无向图,对应的顶点集合和边集合如下:

V(G)= {V1,V2,V3,V4,V5,V6}

E(G)= {(V1,V2),(V1,V3),(V2,V6),(V2,V5),(V2,V4),(V4,V3),(V3,V5),(V5,V6)}

2.有向图(directed graph)

一个图结构中,边是有方向性的,那么这种图就称为有向图,如图三所示。由于图的边有方向性,我们在表示边的时候对两个顶点的顺序就有要求。我们采用尖括号表示有向边,例如<V2,V6>表示从顶点V2到顶点V6,而<V6,V2>表示顶点V6到顶点V2。

3

图三  有向图

对于图三有向图,对应的顶点集合和边集合如下:

V(G)= {V1,V2,V3,V4,V5,V6}

E(G)= {<V2,V1>,<V3,V1>,<V4,V3>,<V4,V2>,<V3,V5>,<V5,V3>,<V2,V5>,<V6,V5>,<V2,V6>,<V6,V2>}

*注意:无向图也可以理解成一个特殊的有向图,就是边互相指向对方节点,A指向B,B又指向A。

3.混合图(mixed graph)

一个图结构中,边同时有的是有方向性有的是无方向型的图。

在生活中混合图这种情况比较常见,比如城市道路中有些道路是单向通行,有的是双向通行。

4.顶点的度

连接顶点的边的数量称为该顶点的度。顶点的度在有向图和无向图中具有不同的表示。对于无向图,一个顶点V的度比较简单,其是连接该顶点的边的数量,记为D(V)。 例如,图二所示的无向图中,顶点V5的度为3。而V6的度为2。

     对于有向图要稍复杂些,根据连接顶点V的边的方向性,一个顶点的度有入度出度之分。

  •  入度是以该顶点为端点的入边数量, 记为ID(V)。
  •  出度是以该顶点为端点的出边数量, 记为OD(V)。

     这样,有向图中,一个顶点V的总度便是入度和出度之和,即D(V) = ID(V) + OD(V)。例如,图三所示的有向图中,顶点V5的入度为3,出度为1,因此,顶点V5的总度为4。

5.邻接顶点

邻接顶点是指图结构中一条边的两个顶点。 邻接顶点在有向图和无向图中具有不同的表示。对于无向图,邻接顶点比较简单。例如,在图二所示的无向图中,顶点V2和顶点V6互为邻接顶点,顶点V2和顶点V5互为邻接顶点等。

对于有向图要稍复杂些,根据连接顶点V的边的方向性,两个顶点分别称为起始顶点(起点或始点)和结束顶点(终点)。有向图的邻接顶点分为两类:

  • 入边邻接顶点:连接该顶点的边中的起始顶点。例如,对于组成<V2,V6>这条边的两个顶点,V2是V6的入边邻接顶点。
  • 出边邻接顶点:连接该顶点的边中的结束顶点。例如,对于组成<V2,V6>这条边的两个顶点,V6是V2的出边邻接顶点。

6.无向完全图

如果在一个无向图中, 每两个顶点之间都存在条边,那么这种图结构称为无向完全图。典型的无向完全图,如图四所示。
4

图四  无向完全图

理论上可以证明,对于一个包含n个顶点的无向完全图,其总边数为n(n-1)/2

比如图四总边数就是5,例子:5*(5-1)/2=10。

7.有向完全图

如果在一个有向图中,每两个顶点之间都存在方向相反的两条边,那么这种图结构称为有向完全图。典型的有向完全图,如图五所示。

5

图五 有向完全图

 

理论上可以证明,对于一个包含n的顶点的有向完全图,其总的边数为:n(n-1)

这是无向完全图的两倍,这个也很好理解,因为每两个顶点之间需要两条边。

8.有向无环图(DAG图)

如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图。有向无环图可以利用在区块链技术中。

9.无权图和有权图

6

这里的权可以理解成一个数值,就是说节点与节点之间这个边是否有一个数值与它对应,对于无权图来说这个边不需要具体的值。对于有权图节点与节点之间的关系可能需要某个值来表示,比如这个数值能代表两个顶点间的距离,或者从一个顶点到另一个顶点的时间,所以这时候这个边的值就是代表着两个节点之间的关系,这种图被称为有权图;

10.图的连通性

图的每个节点不一定每个节点都会被边连接起来,所以这就涉及到图的连通性,如下图:

7

可以发现上面这个图不是完全连通的。

11.简单图 ( Simple Graph)

对于节点与节点之间存在两种边,这两种边相对比较特殊

1.自环边(self-loop):节点自身的边,自己指向自己。

2.平行边(parallel-edges):两个节点之间存在多个边相连接。

8

这两种边都是有意义的,比如从A城市到B城市可能不仅仅有一条路,比如有三条路,这样平行边就可以用到这种情况。不过这两种边在算法设计上会加大实现的难度。而简单图就是不考虑这两种边。

HTTP状态码(记录)

HTTP状态码总的分为五类:

1开头:信息状态码

2开头:成功状态码

3开头:重定向状态码

4开头:客户端错误状态码

5开头:服务端错误状态码

 1XX:信息状态码

状态码 含义 描述
100 继续 初始的请求已经接受,请客户端继续发送剩余部分
101 切换协议 请求这要求服务器切换协议,服务器已确定切换

 2XX:成功状态码

状态码 含义 描述
200 成功 服务器已成功处理了请求
201 已创建 请求成功并且服务器创建了新的资源
202 已接受 服务器已接受请求,但尚未处理
203 非授权信息 服务器已成功处理请求,但返回的信息可能来自另一个来源
204 无内容 服务器成功处理了请求,但没有返回任何内容
205 重置内容 服务器处理成功,用户终端应重置文档视图
206 部分内容 服务器成功处理了部分GET请求

3XX:重定向状态码

状态码 含义 描述
300 多种选择 针对请求,服务器可执行多种操作
301 永久移动 请求的页面已永久跳转到新的url
302 临时移动 服务器目前从不同位置的网页响应请求,但请求仍继续使用原有位置来进行以后的请求
303 查看其他位置 请求者应当对不同的位置使用单独的GET请求来检索响应时,服务器返回此代码
304 未修改 自从上次请求后,请求的网页未修改过
305 使用代理 请求者只能使用代理访问请求的网页
307 临时重定向 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求

4XX:客户端错误状态码

状态码 含义 描述
400 错误请求 服务器不理解请求的语法
401 未授权 请求要求用户的身份演验证
403 禁止 服务器拒绝请求
404 未找到 服务器找不到请求的页面
405 方法禁用 禁用请求中指定的方法
406 不接受 无法使用请求的内容特性响应请求的页面
407 需要代理授权 请求需要代理的身份认证
408 请求超时 服务器等候请求时发生超时
409 冲突 服务器在完成请求时发生冲突
410 已删除 客户端请求的资源已经不存在
411 需要有效长度 服务器不接受不含有效长度表头字段的请求
412 未满足前提条件 服务器未满足请求者在请求中设置的其中一个前提条件
413 请求实体过大 由于请求实体过大,服务器无法处理,因此拒绝请求
414 请求url过长 请求的url过长,服务器无法处理
415 不支持格式 服务器无法处理请求中附带媒体格式
416 范围无效 客户端请求的范围无效
417 未满足期望 服务器无法满足请求表头字段要求

 

5XX:服务端错误状态码

状态码 含义 描述
500 服务器错误 服务器内部错误,无法完成请求
501 尚未实施 服务器不具备完成请求的功能
502 错误网关 服务器作为网关或代理出现错误
503 服务不可用 服务器目前无法使用
504 网关超时 网关或代理服务器,未及时获取请求
505 不支持版本 服务器不支持请求中使用的HTTP协议版本
 
Copyright © 2008-2021 lanxinbase.com Rights Reserved. | 粤ICP备14086738号-3 |