zoukankan      html  css  js  c++  java
  • restTemplate重定向问题 &cookie问题

    最近在做一个转发功能,zuul + ribbon + resttemplate 进行路由、负载、转发的功能

    基本准备就绪,在微信自动登陆那遇到了一个坑,ribbon 系统用resttemplate 转发A系统的资源,在微信自动登陆的地方,A系统重定向到微信的地址,类似下面的代码

    redirect:
    https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3290f3d5****&redirect_uri=http://***.com/weixin/wxAuthRedirect?redirectUrl=http%3A%2F%2F192.168.10.116%3A8081%2Finternal%2Fpage%2Fuser%2Flogin_wx&response_type=code&scope=snsapi_userinfo&state=state#wechat_redirect

    结果resttemplate 自动重定向到本地的地址,如下所示:

    http://192.168.10.116:**/connect/oauth2/authorize**

    仔细思考了下,大概就是resttemplate 的重定向问题,查了查资料,找到一个类HttpComponentsClientHttpRequestFactory,RestTemplate初始化提供了这个类的参数

        /**
         * Create a new instance of the {@link RestTemplate} based on the given {@link ClientHttpRequestFactory}.
         * @param requestFactory HTTP request factory to use
         * @see org.springframework.http.client.SimpleClientHttpRequestFactory
         * @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory
         */
        public RestTemplate(ClientHttpRequestFactory requestFactory) {
            this();
            setRequestFactory(requestFactory);
        }

    HttpComponentsClientHttpRequestFactory继承自ClientHttpRequestFactory,这个类的子类有HttpComponentsClientHttpRequestFactory和SimpleClientHttpRequestFactory

    找到SimpleClientHttpRequestFactory,有如下方法:

    第一种方式:

        /**
         * Template method for preparing the given {@link HttpURLConnection}.
         * <p>The default implementation prepares the connection for input and output, and sets the HTTP method.
         * @param connection the connection to prepare
         * @param httpMethod the HTTP request method ({@code GET}, {@code POST}, etc.)
         * @throws IOException in case of I/O errors
         */
        protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
            if (this.connectTimeout >= 0) {
                connection.setConnectTimeout(this.connectTimeout);
            }
            if (this.readTimeout >= 0) {
                connection.setReadTimeout(this.readTimeout);
            }
    
            connection.setDoInput(true);
    
            if ("GET".equals(httpMethod)) {
                connection.setInstanceFollowRedirects(true);
            }
            else {
                connection.setInstanceFollowRedirects(false);
            }
    
            if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) ||
                    "PATCH".equals(httpMethod) || "DELETE".equals(httpMethod)) {
                connection.setDoOutput(true);
            }
            else {
                connection.setDoOutput(false);
            }
    
            connection.setRequestMethod(httpMethod);
        }

    可以看到setInstanceFollowRedirects,get请求是可以重定向的,其他方法禁止了重定向,于是建个SimpleClientHttpRequestFactory的子类,禁用重定向。

    于是乎 NoRedirectClientHttpRequestFactory.java

    import java.io.IOException;
    import java.net.HttpURLConnection;
    
    import org.springframework.http.client.SimpleClientHttpRequestFactory;
    
    public class NoRedirectClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
    
        @Override
        protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
            // TODO Auto-generated method stub
            super.prepareConnection(connection, httpMethod);
            // 禁止自动重定向
            connection.setFollowRedirects(false);
        }
    }
    NoRedirectClientHttpRequestFactory httpRequestFactory = new NoRedirectClientHttpRequestFactory();
    RestTemplate restTemplate = new RestTemplate(httpRequestFactory);

    接着,似乎更换ClientHttpRequestFactory并不合心意,还是要使用HttpComponentsClientHttpRequestFactory来实现,HttpComponentsClientHttpRequestFactory是可以自定义HttpClient的,于是查到了HttpClient头上,HttpClient是可以设置Redirect的,

    第二种方式:

    HttpClient httpClient = HttpClientBuilder.create()
                    .setRedirectStrategy(new LaxRedirectStrategy())
                    .build();
    httpRequestFactory.setHttpClient(httpClient);
    RestTemplate restTemplate = new RestTemplate(httpRequestFactory);

    默认提供了两个类,DefaultRedirectStrategy和LaxRedirectStrategy,LaxRedirectStrategy继承自DefaultRedirectStrategy

    DefaultRedirectStrategy.java

        /**
         * Redirectable methods.
         */
        private static final String[] REDIRECT_METHODS = new String[] {
            HttpGet.METHOD_NAME,
            HttpHead.METHOD_NAME
        };

    LaxRedirectStrategy.java

    /*
     * ====================================================================
     * Licensed to the Apache Software Foundation (ASF) under one
     * or more contributor license agreements.  See the NOTICE file
     * distributed with this work for additional information
     * regarding copyright ownership.  The ASF licenses this file
     * to you under the Apache License, Version 2.0 (the
     * "License"); you may not use this file except in compliance
     * with the License.  You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing,
     * software distributed under the License is distributed on an
     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     * KIND, either express or implied.  See the License for the
     * specific language governing permissions and limitations
     * under the License.
     * ====================================================================
     *
     * This software consists of voluntary contributions made by many
     * individuals on behalf of the Apache Software Foundation.  For more
     * information on the Apache Software Foundation, please see
     * <http://www.apache.org/>.
     *
     */
    
    package org.apache.http.impl.client;
    
    import org.apache.http.annotation.Contract;
    import org.apache.http.annotation.ThreadingBehavior;
    import org.apache.http.client.methods.HttpDelete;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpHead;
    import org.apache.http.client.methods.HttpPost;
    
    /**
     * Lax {@link org.apache.http.client.RedirectStrategy} implementation
     * that automatically redirects all HEAD, GET, POST, and DELETE requests.
     * This strategy relaxes restrictions on automatic redirection of
     * POST methods imposed by the HTTP specification.
     *
     * @since 4.2
     */
    @Contract(threading = ThreadingBehavior.IMMUTABLE)
    public class LaxRedirectStrategy extends DefaultRedirectStrategy {
    
        public static final LaxRedirectStrategy INSTANCE = new LaxRedirectStrategy();
    
        /**
         * Redirectable methods.
         */
        private static final String[] REDIRECT_METHODS = new String[] {
            HttpGet.METHOD_NAME,
            HttpPost.METHOD_NAME,
            HttpHead.METHOD_NAME,
            HttpDelete.METHOD_NAME
        };
    
        @Override
        protected boolean isRedirectable(final String method) {
            for (final String m: REDIRECT_METHODS) {
                if (m.equalsIgnoreCase(method)) {
                    return true;
                }
            }
            return false;
        }
    
    }

    这就很清晰了,copy一份LaxRedirectStrategy的代码,改写掉REDIRECT_METHODS中的定义方法,如下:

    import org.apache.http.annotation.Contract;
    import org.apache.http.annotation.ThreadingBehavior;
    import org.apache.http.impl.client.DefaultRedirectStrategy;
    
    /**
     * 
    * @ClassName: MyRedirectStrategy 
    * @Description: TODO
    * @author thinklight
    * @date 2018年4月20日 下午2:47:29 
    *
     */
    @Contract(threading = ThreadingBehavior.IMMUTABLE)
    public class MyRedirectStrategy  extends DefaultRedirectStrategy {
    
        public static final MyRedirectStrategy INSTANCE = new MyRedirectStrategy();
    
        /**
         * Redirectable methods.
         */
        private static final String[] REDIRECT_METHODS = new String[] {};
    
        @Override
        protected boolean isRedirectable(final String method) {
            for (final String m: REDIRECT_METHODS) {
                if (m.equalsIgnoreCase(method)) {
                    return true;
                }
            }
            return false;
        }
    }

    ribbon+微信各种重定向问题,解决了。

    第三种方式:

    自己蠢了,今天因为cookie的问题发现了简单的方式

    HttpClient httpClient = HttpClientBuilder.create().disableCookieManagement().disableRedirectHandling().build();

    完整代码如下:

        @Autowired
        RestTemplate restTemplate;
        
        @Bean
        @LoadBalanced
        RestTemplate restTemplate() {
            HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
    //        NoRedirectClientHttpRequestFactory httpRequestFactory = new NoRedirectClientHttpRequestFactory();// 此类型不能使用httpClient
            httpRequestFactory.setConnectionRequestTimeout(2000);
            httpRequestFactory.setConnectTimeout(10000);
            httpRequestFactory.setReadTimeout(7200000);
            // HttpClient httpClient = HttpClientBuilder.create()
            //        .setRedirectStrategy(new MyRedirectStrategy())
            //        .build();
         HttpClient httpClient = HttpClientBuilder.create().disableCookieManagement().disableRedirectHandling().build(); httpRequestFactory.setHttpClient(httpClient); RestTemplate restTemplate
    = new RestTemplate(httpRequestFactory); logger.debug("指定字符编码为UTF-8,原编码为ISO-8859-1"); restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); logger.debug("RestTemple默认能转换为application/json,转换追加text/plain类型"); restTemplate.getMessageConverters().add(new WxMappingJackson2HttpMessageConverter()); return restTemplate; }

    重定向参考:https://www.dozer.cc/2014/05/disable-resttemplate-redirect.html

    cookie参考:https://stackoverflow.com/questions/10175649/resttemplate-and-cookie

    https://stackoverflow.com/questions/22853321/resttemplate-client-with-cookies

  • 相关阅读:
    Solr 集成ikanalyzer
    idea JRebel
    java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the server
    分布式文件上传 spring boot + fastdfs + dropzone
    Docker 安装 fastDFS
    Docker 安装 Nginx
    thymeleaf 声明
    Node.js express
    V for Vendetta
    人性的弱点&&影响力
  • 原文地址:https://www.cnblogs.com/lossingdawn/p/8891234.html
Copyright © 2011-2022 走看看